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

Minix Cross Reference
Minix/kernel/sunether.c


  1 static char rcsid[] = "$Id: sunether.c,v 1.2 1996/08/01 02:08:52 paul Exp $";
  2 
  3 /*
  4  * sunether.c
  5  *
  6  * This file contains a "ethernet device driver" for smx.
  7  *
  8  * The valid messages and their parameters are:
  9  *
 10  *   m_type       DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
 11  * |------------+----------+---------+----------+---------+---------|
 12  * | HARDINT    |          |         |          |         |         |
 13  * |------------|----------|---------|----------|---------|---------|
 14  * | DL_WRITE   | port nr  | proc nr | count    | mode    | address |
 15  * |------------|----------|---------|----------|---------|---------|
 16  * | DL_WRITEV  | port nr  | proc nr | count    | mode    | address |
 17  * |------------|----------|---------|----------|---------|---------|
 18  * | DL_READ    | port nr  | proc nr | count    |         | address |
 19  * |------------|----------|---------|----------|---------|---------|
 20  * | DL_READV   | port nr  | proc nr | count    |         | address |
 21  * |------------|----------|---------|----------|---------|---------|
 22  * | DL_INIT    | port nr  | proc nr | mode     |         | address |
 23  * |------------|----------|---------|----------|---------|---------|
 24  * | DL_GETSTAT | port nr  | proc nr |          |         | address |
 25  * |------------|----------|---------|----------|---------|---------|
 26  * | DL_STOP    | port_nr  |         |          |         |         |
 27  * |------------|----------|---------|----------|---------|---------|
 28  *
 29  * The messages sent are:
 30  *
 31  *   m-type       DL_POR T   DL_PROC   DL_COUNT   DL_STAT   DL_CLCK
 32  * |------------|----------|---------|----------|---------|---------|
 33  * |DL_TASK_REPL| port nr  | proc nr | rd-count | err|stat| clock   |
 34  * |------------|----------|---------|----------|---------|---------|
 35  *
 36  *   m_type       m3_i1     m3_i2       m3_ca1
 37  * |------------+---------+-----------+---------------|
 38  * |DL_INIT_REPL| port nr | last port | ethernet addr |
 39  * |------------|---------|-----------|---------------|
 40  */
 41 
 42 /*
 43  * The smx ethernet device driver operates in a very simple fashion.
 44  * During smx boot, a file the ETHER_FD file descriptor is opened
 45  * as a UDP/IP socket connected to a relay process running under SunOS.
 46  * All outgoing packets are written to this descriptor.  Anything
 47  * received on the descriptor is treated as an incoming ethernet packet,
 48  * and is relayed back to the inet server.  The entry points are:
 49  *
 50  *    se_init - called during bootstrap
 51  *    dp8390_task - the ethernet device driver task's main body
 52  *    se_interrupt - called when an incoming packet has arrived.
 53  *
 54  * During the MINIX bootstrap, se_init is called to inform this driver of its
 55  * "ethernet address", which is actually the UDP address bound to the
 56  * ETHER_FD socket.  se_init also sets up interrupt handling for
 57  * incoming messages.  Later in the bootstrap dp8390_task is called
 58  * as the main body of the ethernet task is created (the name is kept the
 59  * same as the PC function to minimise changes).
 60  *
 61  * Outgoing packets are sent immediately by writing them to ETHER_FD, so
 62  * writing processes are never suspended.  A reading process is suspended
 63  * if there are no input packets waiting.  Up to NR_READ_BUFFERS incoming
 64  * packets can be buffered---any further packets will be dropped.
 65  *
 66  * ISSUES:
 67  *    - if packets are often dropped, then we should change the
 68  *      buffering, so that each packet is stored in a buffer of the
 69  *      appropriate size, and not one of maximum size.
 70  *    - currently, once do_init has been called the device driver remains
 71  *      in the "enabled" state forever.  Should a DL_STOP diable the driver
 72  *      (as in the dp8390 driver)?
 73  *    - currently, broadcasts are permitted whenever networking is enabled.
 74  *      Should we allow them only if DEF_BROAD was specified when the
 75  *      ethernet device driver was enabled?
 76  */
 77 
 78 #include "kernel.h"
 79 #include <minix/callnr.h>
 80 #include <minix/com.h>
 81 #include <net/gen/ether.h>
 82 #include <net/gen/eth_io.h>
 83 
 84 #include <sun/syscall.h>
 85 
 86 #include "proc.h"
 87 #include "assert.h"
 88 
 89 #if ENABLE_NETWORKING
 90 
 91 /*
 92  * There is only 1 "ethernet port"---ETHER_FD!
 93  */
 94 #define SMX_PORT_NR 1
 95 
 96 
 97 /*
 98  * IO vector definition.  The definition, plus the functions for manipulating
 99  * IO vectors, are taken straight from dp8390.c.
100  */
101 #define IOVEC_NR        16
102 
103 typedef struct iovec_dat {
104     iovec_t iod_iovec[IOVEC_NR];
105     int iod_iovec_s;
106     int iod_proc_nr;
107     vir_bytes iod_iovec_addr;
108 } iovec_dat_t;
109 
110 /*
111  * Constants for use with se_rwiovec specifying whether copying is from
112  * the driver to the IO vector (STORE) or vice versa (LOAD).
113  */
114 #define LOAD 1
115 #define STORE 2
116 
117 
118 /*
119  * Information about a reader process awaiting an incoming packet, and about
120  * queued incoming packets, is held in the read_info structure.  The buffered
121  * packets start in read_buffers[first_used], and go to
122  * read_buffers[(first_used + buffs_used - 1) % NR_READ_BUFFERS.  The lengths
123  * of the buffered packets are stored in the corresponding entries of
124  * chars_read.
125  */
126 #define NR_READ_BUFFERS 4
127 
128 typedef struct read_info {
129     int  reader_waiting;           /* Is there a reader waiting? */
130     int  client;                   /* Who is it? */
131     iovec_dat_t read_iovec;        /* Where should the incoming packet go? */
132 
133     int  buffs_used;               /* number of buffer used */
134     int  first_buff;               /* first buffer used */
135     unsigned read_buffers[NR_READ_BUFFERS][ETH_MAX_PACK_SIZE / sizeof(unsigned) + 1];
136     int chars_read[NR_READ_BUFFERS];
137 } read_info_t;
138 
139 
140 static read_info_t read_info;     /* Waiting read and buffered packet info */
141 static ether_addr_t smx_eaddr;    /* Our "ethernet address" */
142 static eth_stat_t estats;         /* Ethernet stats---most unused in smx. */
143 static int smxeth_tasknr;         /* Ethernet driver task number */
144 static int eth_enabled = 0;
145 
146 
147 /*
148  * Local fucntions
149  */
150 static void se_interrupt(int fd);
151 
152 static void do_init(message *mp);
153 static int se_ethernet_on(ether_addr_t *eaddr);
154 static void do_stop(message *mp);
155 
156 static void do_vwrite(message *mp, int vectored);
157 static void do_vread(message *mp, int vectored);
158 static void do_int(void);
159 static int se_flush(int fd);
160 static int se_recv(void);
161 
162 static void se_rwiovec(char *buffer, iovec_dat_t *iovp, vir_bytes count,
163                        int rw);
164 static int calc_iovec_size(iovec_dat_t *iovp);
165 static void se_next_iovec(iovec_dat_t *iovp);
166 static void get_userdata(int user_proc, vir_bytes user_addr, vir_bytes count,
167                          void *loc_addr);
168 static void put_userdata(int user_proc, vir_bytes user_addr, vir_bytes count,
169                          void *loc_addr);
170 
171 static void do_getstat(message *mp);
172 
173 static void se_reply(int whoto, int err, int status, vir_bytes bytes_read);
174 
175 
176 /*
177  * Function: se_init
178  * Parameter: eaddr - our ethernet address.
179  *
180  * Called from kernel main() during booting.  We record our ethernet
181  * address, install se_interrupt as the hander for SIGIO signals on ETHER_FD,
182  * and initialise read_info.
183  */
184 void se_init(char *eaddr)
185 {
186     smx_eaddr = *(ether_addr_t *) eaddr;
187     read_info.reader_waiting = 0;
188     read_info.buffs_used = read_info.first_buff = 0;
189     sunio_install_handler(ETHER_FD, se_interrupt);
190 }
191 
192 
193 /*
194  * Function: se_interrupt
195  * Parameter: fd - SunOS descriptor input is available on.
196  *
197  * An ethernet packet is avilable.  Wakeup the smx ethernet driver to 
198  * read the packet.  This is layer 1 code.
199  */
200 static void se_interrupt(int fd)
201 {
202     interrupt(smxeth_tasknr);
203 }
204 
205 
206 
207 /*
208  * Function: dp8390_task
209  *
210  * The main body of the smx ethernet device driver task.
211  */
212 void dp8390_task(void)
213 {
214     message m;
215     int r;
216   
217     smxeth_tasknr = proc_number(proc_ptr);     /* For se_interrupt to use */
218     
219     while(1) {
220         if ((r = receive(ANY, &m)) != OK) {
221             panic("smx_ether: receive failed", r);
222         }
223         switch (m.m_type)
224         {
225         case DL_WRITE:  do_vwrite(&m, FALSE);   break;
226         case DL_WRITEV: do_vwrite(&m, TRUE);    break;
227         case DL_READ:   do_vread(&m, FALSE);    break;
228         case DL_READV:  do_vread(&m, TRUE);     break;
229         case DL_INIT:   do_init(&m);            break;
230         case DL_GETSTAT: do_getstat(&m);        break;
231         case DL_STOP:   do_stop(&m);            break;
232         case HARD_INT:  do_int();               break;
233         default:
234             panic("smx_ether: illegal message", m.m_type);
235         }
236     }
237 }
238 
239 
240 /*
241  * Function: do_init
242  * Parameter: mp - incoming DL_INIT message
243  *
244  * We mark the device as enabled, and return the address and number of
245  * interfaces.  Initialisation fails if the port number to be initialised
246  * is not 0 (smx supports only 1 interface), if smx has been started
247  * with networking disabled (in which case our ethernet address is all
248  * zeroes) or the mode requested involved mutlicast mode or promiscuous
249  * mode (the relay program needs modifying to handle these).
250  */
251 static void do_init(message *mp)
252 {
253     message reply_mess;
254 
255     reply_mess.m_type = DL_INIT_REPLY;
256 
257     if (mp->DL_PORT != 0 || !se_ethernet_on(&smx_eaddr) ||
258         (mp->DL_MODE & DL_PROMISC_REQ) || (mp->DL_MODE & DL_MULTI_REQ)) {
259         reply_mess.m3_i1  = ENXIO;
260         if (send(mp->m_source, &reply_mess) != OK) {
261             panic("smx_ether: unable to send in DL_INIT", NO_NUM);
262         }
263         return;
264     }
265 
266     memset(&estats, 0, sizeof(estats));
267     reply_mess.m3_i1 = mp->DL_PORT;
268     reply_mess.m3_i2 = SMX_PORT_NR;
269     *(ether_addr_t *) reply_mess.m3_ca1 = smx_eaddr;
270     eth_enabled = 1;
271 
272     if (send(mp->m_source, &reply_mess) != OK) {
273         panic("smx_ether: unable to send in DL_INIT", NO_NUM);
274     }
275 }
276 
277 
278 /*
279  * Function: se_ethernet_on
280  * Parameter: eaddr - our ethernet address
281  * Returns: true of networking is enabled (eaddr is non-zero), false if it
282  *          is disabled.
283  *
284  * The minix bootstrap passes an all zeroes eaddr if networking is off.
285  */
286 static int se_ethernet_on(ether_addr_t *eaddr)
287 {
288     int i;
289     
290     for (i = 0; i < sizeof(eaddr->ea_addr); i++) {
291         if (eaddr->ea_addr[i] != 0) {
292             return 1;
293         }
294     }
295     return 0;
296 }
297 
298 
299 /*
300  * Function: do_stop
301  * Parameter: mp - incoming DL_STOP message
302  *
303  * Currently we just validate the port number.  Should we set eth_enabled
304  * to false here, and discard buffered input?  What if a reader is waiting?
305  */
306 static void do_stop(message *mp)
307 {
308     assert(eth_enabled);
309 
310     if (mp->DL_PORT != 0) {
311         panic("smx_ether: illegal port", mp->DL_PORT);
312     }
313 }
314 
315 
316 /*
317  * Function: do_vwrite
318  * Parameters: mp - incoming DL_WRITE or DL_WRITEV message
319  *             vectored - true if DL_WRITEV, false otherwise
320  *
321  * Sets up an iovec (based on the supplied iovec for a DL_WRITEV,
322  * the buffer supplied for a DL_WRITE), copies the message into
323  * a local buffer, then writes the complete packet to ETHER_FD.
324  */
325 static void do_vwrite(message *mp, int vectored)
326 {
327     iovec_dat_t iovec, tmp_iovec;
328     int count, size;
329     static char write_buffer[ETH_MAX_PACK_SIZE];
330     
331     assert(eth_enabled);
332 
333     if (mp->DL_PORT != 0) {
334         panic("smx_ether: illegal port", mp->DL_PORT);
335     }
336 
337     count = mp->DL_COUNT;
338     iovec.iod_proc_nr = mp->DL_PROC;
339     if (vectored) {
340         /*
341          * A vectored write.  Read in the vector (or at least the first part
342          * of it if it is a long one), and calculate the total number of
343          * bytes in the iovec.  We do this on a copy of the iovec because
344          * calc_iovec_size is destructive.
345          */
346         get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
347                      (count > IOVEC_NR ? IOVEC_NR : count) *
348                      sizeof(iovec_t), iovec.iod_iovec);
349         iovec.iod_iovec_s = count;
350         iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
351         tmp_iovec = iovec;
352         size = calc_iovec_size(&tmp_iovec);
353     } else {  
354         iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
355         iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
356         iovec.iod_iovec_s = 1;
357         iovec.iod_iovec_addr = 0;
358         size = mp->DL_COUNT;
359     }
360     if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE) {
361         panic("smx_ether: invalid packet size", size);
362     }
363 
364     /*
365      * Load the packet from user space, then output it
366      */
367     se_rwiovec(write_buffer, &iovec, size, LOAD);
368     if (SunOS(SYS_write, ETHER_FD, write_buffer, size) != size) {
369         panic("smx_ether: SunOS write failed", errno);
370     }
371 
372     estats.ets_packetT++;
373     se_reply(mp->DL_PROC, OK, DL_PACK_SEND, 0);
374 }
375 
376 
377 /*
378  * Function: do_vread
379  * Parameters: mp - incoming DL_READ or DL_READV message
380  *             vectored - true if DL_READV, false otherwise
381  *
382  * First we set up an iovec (based on the supplied iovec for a DL_READV,
383  * the buffer supplied for a DL_READ).  We then call se_recv which will
384  * transfer a buffered packet and send a reply message, or will tell us
385  * that there are no waiting packets.
386  */
387 static void do_vread(message *mp, int vectored)
388 {
389     iovec_dat_t tmp_iovec;
390     int count;
391     int size;
392 
393     assert(eth_enabled);
394 
395     count = mp->DL_COUNT;
396     if (mp->DL_PORT != 0) {
397         panic("smx_ether: illegal port", mp->DL_PORT);
398     }
399 
400     if (read_info.reader_waiting) {
401         panic("smx_ether: read already in progress", NO_NUM);
402     }
403 
404     read_info.read_iovec.iod_proc_nr = mp->DL_PROC;
405     if (vectored) {
406         /*
407          * A vectored read.  Read in the vector (or at least the first part
408          * of it if it is a long one), and calculate the total number of
409          * bytes in the iovec.  We do this on a copy of the iovec because
410          * calc_iovec_size is destructive.
411          */
412         get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
413                      (count > IOVEC_NR ? IOVEC_NR : count) *
414                      sizeof(iovec_t), read_info.read_iovec.iod_iovec);
415         read_info.read_iovec.iod_iovec_s = count;
416         read_info.read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
417 
418         tmp_iovec = read_info.read_iovec;
419         size = calc_iovec_size(&tmp_iovec);
420     } else {
421         read_info.read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
422         read_info.read_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
423         read_info.read_iovec.iod_iovec_s = 1;
424         read_info.read_iovec.iod_iovec_addr = 0;
425         size = count;
426     }
427     if (size < ETH_MAX_PACK_SIZE) {
428         panic("smx_ether: wrong packet size", size);
429     }
430     read_info.reader_waiting = 1;
431 
432     if (se_recv() == 0) {
433         /*
434          * Nothing was waiting---reply to that effect:
435          */
436         se_reply(mp->DL_PROC, OK, 0, 0);
437     } /* else---se_recv has already replied */
438 }
439 
440 
441 /*
442  * Function: do_int
443  *
444  * One or more packets are available for input.  These packets are read into
445  * the available buffers following any packets already buffered.  Once all
446  * packets have been read, se_recv is called to check to see whether it is now
447  * possible to reply to a previous read.
448  */
449 static void do_int(void)
450 {
451     int num_read;
452     int buff;
453     
454     if (!eth_enabled) {
455         se_flush(ETHER_FD);
456         return;
457     }
458 
459     if (read_info.buffs_used == 0) {
460         buff = read_info.first_buff = 0;
461     } else {
462         buff = (read_info.first_buff + read_info.buffs_used) % NR_READ_BUFFERS;
463     }
464 
465     for (;;) {
466         if (read_info.buffs_used == NR_READ_BUFFERS) {
467             if (se_flush(ETHER_FD)) {
468                 estats.ets_missedP++;
469 /*              printf("Ethernet packet dropped because of full buffers\n");*/
470             }
471             break;
472         }
473         num_read = SunOS(SYS_read, ETHER_FD, read_info.read_buffers[buff],
474                          sizeof(read_info.read_buffers[buff]));
475         if (num_read <= 0) {
476             break;
477         }
478         if (num_read < ETH_MIN_PACK_SIZE) {
479             panic("smx_ether: received ethernet packet too small", num_read);
480         }
481 
482         estats.ets_packetR++;
483         read_info.chars_read[buff] = num_read;
484         read_info.buffs_used++;
485         
486         buff = (buff + 1) % NR_READ_BUFFERS;
487     }
488     se_recv();
489 }
490 
491 
492 /*
493  * Function: se_flush
494  * Parameter: fd - SunOS descriptor
495  * Returns: 1 if anything read from fd, 0 otherwise
496  *
497  * Read and discard all input currently available on fd.
498  */
499 static int se_flush(int fd)
500 {
501     int anything_read = 0;
502     char flush_buff[100];
503 
504     for (;;) {
505         if (SunOS(SYS_read, fd, flush_buff, sizeof(flush_buff)) <= 0) {
506             break;
507         }
508         anything_read = 1;
509     }
510     return anything_read;
511 }
512 
513 
514 /*
515  * Function: se_recv
516  * Returns: 1 if data was transferred and a reply sent to a process waiting
517  *          to read a packet, 0 otherwise.
518  *
519  * If we have one or more buffered packets, and a process waiting to read
520  * a packet, then we can transfer a packet to the reader.
521  */
522 static int se_recv(void)
523 {
524     if (!read_info.reader_waiting || read_info.buffs_used == 0) {
525         return 0;       /* Transfer not possible */
526     }
527 
528     /*
529      * Transfer packet and reply to waiting reader.
530      */
531     se_rwiovec((char *)read_info.read_buffers[read_info.first_buff],
532                   &read_info.read_iovec,
533                   read_info.chars_read[read_info.first_buff], STORE);
534     se_reply(read_info.read_iovec.iod_proc_nr, OK, DL_PACK_RECV,
535              read_info.chars_read[read_info.first_buff]);
536 
537     read_info.reader_waiting = 0;
538     read_info.buffs_used--;
539     if (read_info.buffs_used == 0) {
540         read_info.first_buff = 0;
541     } else {
542         read_info.first_buff = (read_info.first_buff + 1) % NR_READ_BUFFERS;
543     }
544     return 1;
545 }
546 
547                   
548 /*
549  * Function: se_rwiovec
550  * Parameters: buffer - buffer withing smx_ether.
551  *             iovp - details of an iovec in another process
552  *             count - number of bytes to copy
553  *             rw - LOAD if iovp -> buffer; STORE if buffer ->iovp
554  *
555  * Transfer count bytes between buffer and iovp in the direction given
556  * by rw.  This operation is destructive on the information in iovp.
557  */
558 static void se_rwiovec(char *buffer, iovec_dat_t *iovp, vir_bytes count,
559                        int rw)
560 {
561     int bytes, i;
562 
563     i = 0;
564     while (count > 0) {
565         if (i >= IOVEC_NR) {
566             /*
567              * Need next section of the io vector
568              */
569             se_next_iovec(iovp);
570             i = 0;
571             continue;
572         }
573 
574         assert(i < iovp->iod_iovec_s);
575         bytes = iovp->iod_iovec[i].iov_size;
576         if (bytes > count) {
577             bytes = count;
578         }
579 
580         if (rw == LOAD) {
581             get_userdata(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr,
582                           bytes, buffer);
583         } else {
584             put_userdata(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr,
585                           bytes, buffer);
586         }
587 
588         count -= bytes;
589         buffer += bytes;
590         i++;
591     }
592     assert(count == 0);
593 }
594 
595 
596 /*
597  * Function: calc_iovec_size
598  * Parameter: iovp - iovec whose size is to be determined.
599  * Returns: the number of bytes of storage within the iovec
600  *
601  * Calculate the size of a request. Note that the iovec_dat
602  * structure will be unusable after calc_iovec_size.
603  */
604 static int calc_iovec_size(iovec_dat_t *iovp)
605 {
606     int size;
607     int i;
608 
609     size = 0;
610     i= 0;
611     while (i < iovp->iod_iovec_s) {
612         if (i >= IOVEC_NR) {     /* get the next chunk */
613             se_next_iovec(iovp);
614             i = 0;
615             continue;
616         }
617         size += iovp->iod_iovec[i].iov_size;
618         i++;
619     }
620     return size;
621 }
622 
623 
624 /*
625  * Function: se_next_iovec
626  * Parameter: iovp - iovec_dat that we want the next chunk of
627  *
628  * Load the next chunk of the iovec whose detail are recorded in iovp
629  */
630 static void se_next_iovec(iovec_dat_t *iovp)
631 {
632     assert(iovp->iod_iovec_s > IOVEC_NR);
633 
634     iovp->iod_iovec_s -= IOVEC_NR;
635 
636     iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
637 
638     get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr, 
639                  (iovp->iod_iovec_s > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s)
640                  * sizeof(iovec_t), iovp->iod_iovec); 
641 }
642 
643 
644 /*
645  * Function: get_userdata
646  * Parameters: user_proc - process data is coming from
647  *             user_addr - address of buffer in user_proc
648  *             count - number of bytes to transfer
649  *             loc_addr - address of local buffer to copy the user buffer to
650  *
651  * Copy a buffer from user_proc to a local buffer.
652  */
653 static void get_userdata(int user_proc, vir_bytes user_addr, vir_bytes count,
654                          void *loc_addr)
655 {
656     phys_bytes src;
657 
658     src = numap(user_proc, user_addr, count);
659     if (!src) {
660         panic("smx_ether: umap failed", NO_NUM);
661     }
662 
663     phys_copy(src, vir2phys(loc_addr), (phys_bytes) count);
664 }
665 
666 
667 /*
668  * Function: put_userdata
669  * Parameters: user_proc - process data is going to
670  *             user_addr - address of buffer in user_proc
671  *             count - number of bytes to transfer
672  *             loc_addr - address of local buffer to copy the user buffer from
673  *
674  * Copy a buffer from a local buffe to user_proc.
675  */
676 static void put_userdata(int user_proc, vir_bytes user_addr, vir_bytes count,
677                          void *loc_addr)
678 {
679     phys_bytes dst;
680 
681     dst = numap(user_proc, user_addr, count);
682     if (!dst) {
683         panic("smx_ether: umap failed", NO_NUM);
684     }
685     phys_copy(vir2phys(loc_addr), dst, (phys_bytes) count);
686 }
687 
688 
689 /*
690  * Function: do_getstat
691  * Parameters: mp - incoming DL_GETSTAT message
692  *
693  * Copies the ethernet statistics to the requersting process.
694  */
695 static void do_getstat(message *mp)
696 {
697     if (mp->DL_PORT != 0) {
698         panic("smx_ether: illegal port", mp->DL_PORT);
699     }
700 
701     assert(eth_enabled);
702 
703     put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
704                  (vir_bytes) sizeof(estats), &estats);
705     se_reply(mp->DL_PROC, OK, 0, 0);
706 }
707 
708 
709 
710 /*
711  * Function: se_reply
712  * Parameters: whoto - who to reply to
713  *             err - the error status of the request made
714  *             status - a bit map, containing details on packet
715  *                      send and receive
716  *             bytes_read - number of bytes read (only non-zero if
717  *                          status includes DL_PACK_RECV).
718  *
719  * Send a reply to a previous request message.
720  */
721 static void se_reply(int whoto, int err, int status, vir_bytes bytes_read)
722 {
723     message reply;
724     int r;
725 
726     reply.m_type = DL_TASK_REPLY;
727     reply.DL_PORT = 0;             /* The only port under smx */
728     reply.DL_PROC = whoto;
729     reply.DL_STAT = status | ((u32_t) err << 16);
730     reply.DL_COUNT = bytes_read;
731     reply.DL_CLCK = get_uptime();
732     r = send(whoto, &reply);
733     if (r < 0) {
734         panic("smx_ether: send failed:", r);
735     }
736 }
737 
738 #endif /* ENABLE_NETWORKING */
739 

~ [ 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.