~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
cvs/emstar/link/liblink/link_user.c


  1 /*
  2  *
  3  * Copyright (c) 2003 The Regents of the University of California.  All 
  4  * rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  *
 10  * - Redistributions of source code must retain the above copyright
 11  *   notice, this list of conditions and the following disclaimer.
 12  *
 13  * - Neither the name of the University nor the names of its
 14  *   contributors may be used to endorse or promote products derived
 15  *   from this software without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 20  * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  *
 29  */
 30  
 31 
 32 /*
 33  * utilities that help link users (i.e. clients that use device drivers)
 34  *
 35  * $Id: link_user.c,v 1.32 2007-12-08 04:05:04 girod Exp $
 36  */
 37 
 38 char link_user_cvsid[] = "$Id: link_user.c,v 1.32 2007-12-08 04:05:04 girod Exp $";
 39 
 40 #include <stdio.h>
 41 #include <stdlib.h>
 42 #include <sys/types.h>
 43 #include <sys/stat.h>
 44 #include <fcntl.h>
 45 #include <time.h>
 46 
 47 #include "liblink_i.h"
 48 
 49 int lu_check_status(lu_context_t *lu);
 50 
 51 /*
 52  * This is called every time a packet arrives from the underlying
 53  * packetdev.  We check to make sure it's a valid link packet, then
 54  * pass it up.
 55  */
 56 static int lu_input_handler(void *pkt, ssize_t len, pd_client_context_t *pdc)
 57 {
 58   lu_context_t *lu = (lu_context_t *) pd_client_opts(pdc)->data;
 59   link_pkt_t *link_pkt = (link_pkt_t *) pkt;
 60 
 61   /* Make sure there's a receive callback! */
 62   if (!lu->opts.receive) {
 63     elog(LOG_ERR, "receiving packet with no callback; shouldn't happen!");
 64     free(pkt);
 65     return EVENT_DONE;
 66   }
 67 
 68   /* All drivers provide packets with this common header */
 69   if (len < sizeof(link_pkt_t)) {
 70     elog(LOG_WARNING, "short packet (%d bytes) from %s", (int)len, 
 71          lu_name(lu, NULL));
 72     free(pkt);
 73     return EVENT_RENEW;
 74   }
 75 
 76   /* Make sure we aren't passing a packet type that the user didn't ask for */
 77   if (lu->opts.opts.pkt_type && link_pkt->type != lu->opts.opts.pkt_type) {
 78     pd_client_filter_failure(pdc);
 79     free(pkt);
 80     return EVENT_RENEW;
 81   }
 82 
 83   /* Call the user's callback and return their retval */
 84   return (lu->opts.receive)(lu, link_pkt, len - sizeof(link_pkt_t));
 85 }
 86 
 87 
 88 
 89 /*
 90  * This is called when there's space in the link device's outgoing
 91  * queue.  If you've provided a "writable" callback when opening the
 92  * link, use link_writable_cb_set_enable to activate and deactivate
 93  * it.  When active, your callback will be called every time there is
 94  * space available in the queue (i.e. link_send will succeed without
 95  * EAGAIN).  Disable the writable callback if you have nothing to
 96  * send, or you'll get a continuous stream of "writeable"
 97  * notifications.
 98  */
 99 static int lu_writable_handler(pd_client_context_t *pdc)
100 {
101   lu_context_t *lu = (lu_context_t *) pd_client_opts(pdc)->data;
102 
103   /* Make sure there's a writable callback! */
104   if (!lu->opts.writable) {
105     elog(LOG_ERR, "writeable, but no callback; shouldn't happen!");
106     return EVENT_DONE;
107   }
108 
109   return (lu->opts.writable)(lu);
110 }
111 
112 
113 static int lu_status_handler(void *new_buffer, size_t size, void *data)
114 {
115   lu_context_t *lu = (lu_context_t *) data;
116   link_status_t *stat = (link_status_t *)new_buffer;
117 
118   /* check size */
119   if (size != sizeof(link_status_t)) {
120     elog(LOG_WARNING, "Got link status, wrong size: %d/%d",
121          (int) size, (int) sizeof(link_status_t));
122     goto out;
123   }
124 
125   /* valid now */
126   lu->status_valid = 1;
127 
128   /* copy status */
129   memmove(&(lu->last_status), stat, sizeof(link_status_t));
130 
131   /* notify */
132   if (lu->opts.status_notify) lu->opts.status_notify(lu);
133 
134  out:
135   if (new_buffer) free(new_buffer);
136   return EVENT_RENEW;
137 }
138 
139 
140 static
141 int lu_configure_delay(void *data, int interval, g_event_t *ev)
142 {
143   lu_context_t *lu = (lu_context_t *) data;
144   if (lu->pdc == NULL) {
145     elog(LOG_WARNING, "delayed configure callback failed???..");
146   }
147   else 
148     lu->opts.configure(lu);
149   return TIMER_DONE;
150 }
151 
152 
153 /* enable the link user to reconfigure the link on (re)open */
154 int lu_configure_handler(int fd, pd_client_context_t *pdc)
155 {
156   /* note: this can be called before the lu is finished initializing.
157    * lu is valid but lu->pdc may not be */
158 
159   lu_context_t *lu = (lu_context_t *) pd_client_opts(pdc)->data;
160 
161   /* set promisc from opts */
162   if (ioctl(fd, LINK_SET_PROMISC, &lu->opts.promisc) < 0) {
163     elog(LOG_WARNING, "Error setting promiscuous mode: %m");
164   }
165 
166   /* call optional configure handler */
167   if (lu && lu->opts.configure) {
168     /* configure is sometimes called before initialization has completed.. */
169     if (lu->pdc == NULL) {
170       elog(LOG_DEBUG(0), "delaying configure callback..");
171       g_timer_add(0, lu_configure_delay, lu, NULL, &(lu->configure_delay));
172     }
173     else 
174       lu->opts.configure(lu);
175   }
176 
177   return EVENT_RENEW;
178 }
179 
180 
181 /*
182  * link_open: API function called by users when they want to start
183  * using the link.  link_opts is a struct containing options
184  * describing the desired link; see definition of link_opts for
185  * details.
186  *
187  * If the open is successful, link_open returns 0, and writes the link
188  * context to "ref" (a pointer provided by the user).  If it fails,
189  * link_open returns -1 and sets errno appropriately.
190  *
191  * If a "receive" callback is set in the link_opts structure, it will
192  * be called when packets arrive.
193  */
194 gint lu_open(lu_opts_t *opts, lu_context_t **ref)
195 {
196   pd_filter_t *filter;
197   int retval;
198 
199   /* link device state */
200   lu_context_t *lu = g_new0(lu_context_t, 1);
201   
202   /* make sure we allocated this sucker */
203   if (lu == NULL) {
204     retval = -ENOMEM;
205     goto done;
206   }
207 
208   /* make sure the options are valid */
209   if (opts == NULL) {
210     elog(LOG_ERR, "invalid link options (null)");
211     retval = -EINVAL;
212     goto done;
213   }
214 
215   /* copy the options to be used */
216   lu->opts = *opts;
217 
218   /* copy the name */
219   lu->opts.opts.name = g_strdup(opts->opts.name);
220   
221   {
222     /* configure the packet client options */
223     pd_client_opts_t pd_opts = {
224       data: lu,
225       q_opts: lu->opts.opts.q_opts,
226       devname: lu_name(lu, LINK_DATA_SUBDEV),
227       configure: lu_configure_handler,
228       blocking_writes: lu->opts.blocking_writes
229     };
230   
231     if (lu->opts.receive)
232       pd_opts.receive = lu_input_handler;
233   
234     if (lu->opts.writable)
235       pd_opts.writable = lu_writable_handler;
236 
237     /* convert the user's packettype into a pd filter */
238     filter = &(pd_opts.pd_filter);
239     memset(filter, 0, sizeof(pd_filter_t));
240     if (lu->opts.opts.pkt_type != PKT_TYPE_ALL) {
241       filter->len = sizeof(lu->opts.opts.pkt_type);
242       memcpy(&(filter->data), &(lu->opts.opts.pkt_type), 
243              sizeof(lu->opts.opts.pkt_type));
244     }
245 
246     /* try to open the selected file */
247     if (pd_client_open(&pd_opts, &lu->pdc) < 0) {
248       retval = -1;
249       goto done;
250     }
251   }
252 
253   /* open the status device */
254   {
255     status_client_opts_t opts = {
256       private_data: lu,
257       devname: lu_name(lu, LINK_STATUS_SUBDEV),
258       handler: lu_status_handler
259     };
260 
261     if (g_status_client_full(&opts, &(lu->scc)) < 0) {      
262       elog(LOG_WARNING, "Can't open link status device: %m");
263       retval = -1;
264       goto done;
265     }
266   }
267   
268   /* success! */
269   retval = 0;
270 
271 done:
272 
273   /* if we've had an error, close and dealloc */
274   if (retval < 0) {
275     lu_destroy(lu);
276     lu = NULL;
277   }
278 
279   /* write the link context (or, a NULL link context pointer) to the
280    * user's provided reference, if any */
281   if (ref) {
282     if (*ref) {
283       elog(LOG_WARNING, "Destroying link user before reusing reference");
284       lu_destroy(*ref);
285     }
286     *ref = lu;
287   }
288 
289   /* and return either success or failure with errno properly set */
290   if (retval < 0) {
291     errno = -retval;
292     retval = -1;
293   } else {
294     errno = 0;
295     retval = 0;
296   }
297 
298   /* force read now, after the ref is populated */
299   if (retval == 0)
300     lu_check_status(lu);
301 
302   return retval;
303 }
304 
305 
306 void lu_destroy(lu_context_t *lu)
307 {
308   if (lu) {
309     /* clear reference */
310     if (lu->ref)
311       *(lu->ref) = NULL;
312     
313     /* destroy packet and status clients */
314     pd_client_destroy(lu->pdc);
315     g_status_client_destroy(lu->scc);
316 
317     /* kill scheduling timer */
318     g_event_destroy(lu->configure_delay);
319 
320     /* free memory */
321     g_free(lu->opts.opts.name);
322     g_free(lu);
323   }
324 }
325 
326 
327 int lu_poll(lu_context_t *lu)
328 {
329   if (lu) return pd_client_poll(lu->pdc);
330   return -1;
331 }
332 
333 
334 /* Returns -1 on failure, and 0 on success */
335 gint lu_send_simple(lu_context_t *lu, if_id_t dst, if_id_t src, int pkt_type,
336                 void* pkt, ssize_t pkt_len)
337 {
338   link_pkt_t lhdr = {
339     dst: {
340       id: dst,
341     },
342     src: {
343       id: src,
344     }, 
345     type: pkt_type,
346   };
347 
348   buf_t* buf = buf_new();
349   bufcpy(buf, &lhdr, sizeof(link_pkt_t));
350   if (pkt_len > 0) bufcpy(buf, pkt, pkt_len);
351   elog(LOG_DEBUG(1), "Sending pkt of size: %d\n",
352        (int)(buf->len - sizeof(link_pkt_t)));
353   if (lu_send(lu, (link_pkt_t *)buf->buf,
354        buf->len - sizeof(link_pkt_t)) < 0) {
355     elog(LOG_ERR, "ERROR Unable to send packet on link %m!\n");
356     return -1;
357   }
358   buf_free(buf);
359   return 0;
360 }
361 
362 int lu_set_blocking_mode(lu_context_t *lu, int blocking)
363 {
364   if (lu) return pd_client_set_blocking_mode(lu->pdc, blocking);
365   return -1;
366 }
367 
368 /*
369  * send a packet on the link.  data_len is the size of the data, NOT
370  * including the link_pkt_t header.
371  */
372 gint lu_send(lu_context_t *lu, link_pkt_t *pkt, ssize_t data_len)
373 {
374   int status;
375 
376   if (pkt->type == PKT_TYPE_ALL) {
377     elog(LOG_ERR, "invalid packet type %d (uninitialized pkt_type field?)", 
378          pkt->type);
379     errno = EINVAL;
380     return -1;
381   }
382 
383   if (lu==NULL) {
384           elog(LOG_ERR, "NULL link context pointer");
385           errno = EFAULT;
386           return -1;
387   }
388 
389   status = pd_client_send(lu->pdc, pkt, data_len + sizeof(link_pkt_t));
390   if ((status < 0) && (errno == EMSGSIZE)) {
391     errno = EMSGSIZE;
392   }
393 
394   return status;
395 }
396 
397 
398 /*
399  * enable or disable the delivery of callback notification
400  */
401 void lu_writable_cb_set_enable(lu_context_t *lu, int enable)
402 {
403   pd_client_writable_cb_set_enable(lu->pdc, enable);
404 }
405 
406 void lu_readable_cb_set_enable(lu_context_t *lu, int enable)
407 {
408   pd_client_readable_cb_set_enable(lu->pdc, enable);
409 }
410 
411 int lu_writable_cb_get_enable(lu_context_t *lu)
412 {
413   return pd_client_writable_cb_get_enable(lu->pdc);
414 }
415 
416 int lu_readable_cb_get_enable(lu_context_t *lu)
417 {
418   return pd_client_readable_cb_get_enable(lu->pdc);
419 }
420 
421 
422 /*
423  * send an ioctl on a link
424  */
425 gint lu_ioctl(lu_context_t *lu, int cmd, void *arg)
426 {
427   return pd_client_ioctl(lu->pdc, cmd, arg);
428 }
429 
430 
431 int lu_set_promisc(lu_context_t *lu, int enable)
432 {
433   return lu_ioctl(lu, LINK_SET_PROMISC, &enable);
434 }
435 
436 
437 /*
438  *  status accessors
439  */
440 
441 int lu_check_status(lu_context_t *lu)
442 {
443   if (!lu->status_valid) {
444     if (g_status_client_force_read(lu->scc) >= 0) {
445       lu->status_valid = 1;
446     }
447   }
448   return lu->status_valid;
449 }
450 
451 gint lu_get_mtu(lu_context_t *lu, uint16_t *mtu)
452 {
453   if (lu_check_status(lu)) {
454     *mtu = lu->last_status.MTU;
455     return 0;
456   }
457   return -1;
458 }
459 
460 
461 gint lu_get_if_id(lu_context_t *lu, if_id_t *if_id)
462 {
463   if (lu_check_status(lu)) {
464     *if_id = lu->last_status.if_id;
465     return 0;
466   }
467   return -1;
468 }
469 
470 
471 int lu_get_root_link_dev(lu_context_t *lu, char *device)
472 {
473   device[0] = 0;
474   if (lu) {
475     link_status_t status;
476     if (lu_status(lu, &status) == 0) {
477       char *first_comma = strchr(status.trace, ',');
478       if (first_comma) {
479         char *second_comma = strchr(first_comma+1, ',');
480         if (second_comma) {
481           strncpy(device, first_comma+1, second_comma - first_comma - 1);
482           device[second_comma - first_comma - 1] = 0;
483         }
484         else
485           strcpy(device, first_comma+1);
486         if (device[0])
487           return 0;     
488       }
489     }
490   }
491   return -1;
492 }
493 
494 
495 gint lu_status(lu_context_t *lu, link_status_t *status_return)
496 {
497   if (lu_check_status(lu)) {
498     *status_return = lu->last_status;
499     return 0;
500   }
501   return -1;
502 }
503 
504 
505 gint lu_force_status(lu_context_t *lu, link_status_t *status_return)
506 {
507   /* $$$$ send forced refresh command $$$$ */
508   /* $$$$ wait for response?   or just asynch?  */
509   return lu_status(lu, status_return);
510 }
511 
512 
513 /* Accessor functions used to get info out of a link user context */
514 lu_opts_t *lu_opts(lu_context_t *lu)
515 {
516   return (lu) ? &lu->opts : NULL;
517 }
518 
519 void *lu_data(lu_context_t *lu)
520 {
521   return (lu) ? lu->opts.opts.data : NULL;
522 }
523 
524 /* get the name of the link */
525 char *lu_name(lu_context_t *lu, char *suffix)
526 {
527   return lu ? link_name(&(lu->opts.opts), suffix) : NULL;
528 }
529 
530 
531 int lu_printf_command(lu_context_t *lu, const char *fmt, ...)
532 {
533   va_list ap;
534   static char str[MAX_LINE];
535 
536   va_start(ap, fmt);
537   vsnprintf(str, sizeof(str), fmt, ap);
538   va_end(ap);
539 
540   return write_to_file(lu_name(lu, LINK_COMMAND_SUBDEV), str);
541 }
542 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.