Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: netsim.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | /* icq: | |
22 | * SNOOP | |
23 | * | |
24 | * "netsim.cc", low level communications between blaze and switchsim, syncsim. | |
25 | * | |
26 | * There are two major service types: | |
27 | * | |
28 | * Global-Time-Sync packets (simple C strings) | |
29 | * Network packets (network-packet plus 8-byte switchsim header | |
30 | * containing length and timing info) | |
31 | * | |
32 | * There are three major implementations: | |
33 | * | |
34 | * Socket-based, | |
35 | * Mmap-based, | |
36 | * Snoop-based. | |
37 | * | |
38 | * | |
39 | * Someday the UI for disconnect/reconnect will be moved here too, no | |
40 | * need to duplicate that in every net-device-sim... | |
41 | * | |
42 | * netsim_connect() name parsing: | |
43 | * | |
44 | * "sync:host/port" | |
45 | * "switch:host/port" | |
46 | * | |
47 | * currently we only support socket-based, and it is not yet part of the | |
48 | * name parsing... | |
49 | */ | |
50 | ||
51 | /* --->> NOTICE THERE ARE NO BLAZE INCLUDES HERE, KEEP IT THAT WAY !!! <<--- */ | |
52 | ||
53 | /* standard C includes */ | |
54 | #include <stdio.h> | |
55 | #include <stdlib.h> | |
56 | #include <errno.h> | |
57 | #include <unistd.h> | |
58 | #include <strings.h> | |
59 | #include <assert.h> | |
60 | #include <stdarg.h> | |
61 | ||
62 | /* unix/Solaris includes */ | |
63 | #include <signal.h> | |
64 | #include <sys/types.h> | |
65 | #include <sys/socket.h> | |
66 | #include <sys/stat.h> | |
67 | #include <sys/mman.h> | |
68 | #include <sys/utsname.h> | |
69 | #include <net/if.h> | |
70 | #include <netinet/if_ether.h> | |
71 | #include <rpc/xdr.h> | |
72 | #include <synch.h> | |
73 | #include <fcntl.h> | |
74 | #include <netdb.h> | |
75 | #include <stropts.h> /* strbuf, getmsg, putmsg */ | |
76 | #include <sys/dlpi.h> /* dlbindack, dlokack, etc..., DL_ defines... */ | |
77 | ||
78 | /* this file's public include */ | |
79 | #include "netsim.h" | |
80 | ||
81 | /* private includes */ | |
82 | #include "eth.h" /* general purpose ethernet packet decoder */ | |
83 | ||
84 | ||
85 | ||
86 | /* bogus legacy globals ---------------------------------------- */ | |
87 | int netsim_switch_flag = 1; | |
88 | char netsim_switch_server_name[MAXPATHLEN] = {'\0'}; | |
89 | char netsim_switch_ipc_type[MAXPATHLEN] = {'\0'}; | |
90 | char netsim_mmap_dir[MAXPATHLEN] = {'\0'}; | |
91 | int netsim_ipc_type = NETSIM_IPC_SOCKET; | |
92 | ||
93 | ||
94 | ||
95 | ||
96 | ||
97 | ||
98 | ||
99 | /* configuration for this file */ | |
100 | #define SIMGE_SWITCH_VERSION "1.0" /* expecting switchsim to support */ | |
101 | #define USE_POLL 1 /* cant see why this is used, PAL*/ | |
102 | ||
103 | int netsim_debug = 0; /* debug level */ | |
104 | ||
105 | ||
106 | ||
107 | ||
108 | ||
109 | /* swtchdr.pkt_type values -------------------------------------- */ | |
110 | ||
111 | #define PKT_DATA 0 | |
112 | #define PKT_CTRL_VERSION 1 | |
113 | #define PKT_CTRL_IPC_TYPE 2 | |
114 | #define PKT_CTRL_KEY_TYPE 3 | |
115 | #define PKT_CTRL_INIT_END 4 | |
116 | ||
117 | #define PKT_CTRL_ACK_BASE 100 | |
118 | ||
119 | #define PKT_CTRL_VERSION_OK (PKT_CTRL_ACK_BASE + PKT_CTRL_VERSION) | |
120 | #define PKT_CTRL_IPC_TYPE_OK (PKT_CTRL_ACK_BASE + PKT_CTRL_IPC_TYPE) | |
121 | #define PKT_CTRL_KEY_TYPE_OK (PKT_CTRL_ACK_BASE + PKT_CTRL_KEY_TYPE) | |
122 | #define PKT_CTRL_INIT_END_OK (PKT_CTRL_ACK_BASE + PKT_CTRL_INIT_END) | |
123 | ||
124 | #define PKT_CTRL_ERROR 400 | |
125 | ||
126 | #define PKT_CTRL_IPC_SOCKET 0 | |
127 | #define PKT_CTRL_IPC_MMAP 1 | |
128 | ||
129 | #define PKT_CTRL_KEY_ETH 0 | |
130 | #define PKT_CTRL_KEY_IP 1 | |
131 | ||
132 | ||
133 | ||
134 | ||
135 | /* | |
136 | * forward decls ----------------------------------------------------- | |
137 | */ | |
138 | void vargs_error(int thresh, const char *fmt, ...); | |
139 | static int | |
140 | switch_negotiate(int fd, int ipc_type, int key_type, char *mmap_idstr, int mmap_file_size); | |
141 | static int | |
142 | ipc_socket_read_pkt(int fd, char *pkt, int maxlen, swtchdr *hdr, int timout); | |
143 | static int | |
144 | ipc_mmap_read_pkt(int fd, char *pkt, int maxlen, swtchdr *hdr, int timout); | |
145 | static int | |
146 | ipc_socket_write_pkt(int fd, char *pkt, int len, swtchdr *hdr); | |
147 | static int | |
148 | ipc_mmap_write_pkt(int fd, char *pkt, int pktlen, swtchdr *hdr); | |
149 | ||
150 | ||
151 | ||
152 | /* | |
153 | * -------- global variables -------------------------------------------------- | |
154 | */ | |
155 | ||
156 | enum { _NONE=0, _SWITCH, _SYNC }; // service types | |
157 | enum { _CLOSED=0, _SOCKET, _MMAP, _SNOOP }; // service implementations | |
158 | ||
159 | static struct { | |
160 | int service; /* _SWITCH, _SYNC */ | |
161 | int implt; /* _SOCKET, _MMAP, _SNOOP */ | |
162 | ||
163 | } info[ FD_SETSIZE ]; /* indexed by `fd' of open socket/mmap/snoop file */ | |
164 | ||
165 | ||
166 | ||
167 | ||
168 | ||
169 | ||
170 | ||
171 | ||
172 | ||
173 | //////////////////////////////////////////////////////////////////////////////// | |
174 | // // | |
175 | // These are the four public interface functions connect, get, put, close // | |
176 | // // | |
177 | //////////////////////////////////////////////////////////////////////////////// | |
178 | ||
179 | ||
180 | ||
181 | /* ------------------------------ simplified ---------------------------------- | |
182 | * ...currently only handles socket, not mmap, not snoop... | |
183 | * | |
184 | */ | |
185 | int netsim_connect(const char *switchandport) | |
186 | { | |
187 | int ipc_type = PKT_CTRL_IPC_SOCKET; /* vs mmap */ | |
188 | int key_type = 0; /* ip vs mac routing in switchsim */ | |
189 | ||
190 | const char * p, * q; | |
191 | int i, portno, service; | |
192 | ||
193 | char host[ MAXPATHLEN ]; | |
194 | struct hostent *server; | |
195 | struct sockaddr_in serv_addr; | |
196 | int sockfd; | |
197 | ||
198 | ||
199 | p = switchandport; | |
200 | if (strncmp (switchandport, "sync:", 5) == 0) { // "sync:" | |
201 | service = _SYNC; | |
202 | p += 5; | |
203 | } else if (strncmp (switchandport, "switch:", 7) == 0) { // "switch:" | |
204 | service = _SWITCH; | |
205 | p += 7; | |
206 | } else { | |
207 | service = _SWITCH; | |
208 | } | |
209 | ||
210 | if ((q = strrchr (p, '/')) != NULL) { // "host/port" | |
211 | i = q - p; | |
212 | strncpy (host, p, MAXPATHLEN); | |
213 | host[ i ] = '\0'; | |
214 | portno = atoi (&host[ i+1 ]); | |
215 | } else { | |
216 | strncpy (host, p, MAXPATHLEN); | |
217 | if (service == _SYNC) | |
218 | portno = SYNC_DEFAULT_PORT; | |
219 | else | |
220 | portno = SWITCH_DEFAULT_PORT; | |
221 | } | |
222 | ||
223 | if (netsim_debug) fprintf(stderr,"netsim_connect %s: \"%s\", %d\n", | |
224 | (service == _SYNC ? "sync" : "switch"), host, portno); | |
225 | ||
226 | ||
227 | sockfd = socket(AF_INET, SOCK_STREAM, 0); /*--SOCKET--*/ | |
228 | if (sockfd < 0) { | |
229 | fprintf(stderr, "ERROR: tryconnect: socket: %s \n", strerror(errno)); | |
230 | return -1; | |
231 | } | |
232 | ||
233 | server = gethostbyname(host); /*--GETHOSTBYNAME--*/ | |
234 | if (server == NULL) { | |
235 | fprintf(stderr, "ERROR: tryconnect: gethostbyname: %s \n", strerror(h_errno)); | |
236 | close(sockfd); | |
237 | return -1; | |
238 | } | |
239 | ||
240 | bzero((char *) &serv_addr, sizeof(struct sockaddr_in)); | |
241 | serv_addr.sin_family = AF_INET; | |
242 | bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); | |
243 | serv_addr.sin_port = htons(portno); /*--CONNECT--*/ | |
244 | if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){ | |
245 | fprintf(stderr, "ERROR: tryconnect: connect: %s \n", strerror(errno)); | |
246 | close(sockfd); | |
247 | return -1; | |
248 | } | |
249 | ||
250 | if (netsim_debug) fprintf(stderr,"netsim_connect fd = %d\n", sockfd); | |
251 | ||
252 | if (service == _SYNC) { | |
253 | info[ sockfd ].service = _SYNC; | |
254 | ||
255 | } else /*service == _SWITCH*/ { /*--negotiate--*/ | |
256 | if (switch_negotiate(sockfd, ipc_type, key_type, NULL, 0) < 0) { | |
257 | fprintf(stderr, "ERROR: tryconnect: negotiate: with %s failed. \n", | |
258 | host); | |
259 | close(sockfd); | |
260 | return -1; | |
261 | } | |
262 | info[ sockfd ].service = _SWITCH; | |
263 | } | |
264 | ||
265 | info[ sockfd ].implt = _SOCKET; | |
266 | return sockfd; | |
267 | } | |
268 | ||
269 | ||
270 | ||
271 | /* ------------------------------ simplified ---------------------------------- | |
272 | */ | |
273 | int netsim_close (int fd) | |
274 | { | |
275 | close (fd); | |
276 | info[ fd ].service = _NONE; | |
277 | info[ fd ].implt = _CLOSED; | |
278 | return 0; | |
279 | } | |
280 | ||
281 | ||
282 | ||
283 | ||
284 | ||
285 | /* ------------------------------ simplified ---------------------------------- | |
286 | * result < 0 error | |
287 | * result = 0 connection closed, or errno = EINTR (from SIGUSR1) | |
288 | * result > 0 success, --> actual bytes read is returned in hdr->pkt_len <-- | |
289 | */ | |
290 | ||
291 | int | |
292 | netsim_getmsg(int fd, char * buf, int maxlen, swtchdr * hdr) | |
293 | { | |
294 | int result; | |
295 | ||
296 | if (info[ fd ].service == _SYNC) { | |
297 | ||
298 | if (info[fd].implt == _SOCKET) { | |
299 | /* ? read, ? fread, ? fgets, ? getmsg, ? ... */ | |
300 | int flags = 0; | |
301 | struct strbuf ctrlbuf; | |
302 | struct strbuf databuf; | |
303 | databuf.maxlen = maxlen; | |
304 | databuf.buf = buf; | |
305 | result = getmsg (fd, NULL/*ctrlbuf*/, &databuf, NULL/*flagsp*/); | |
306 | /* man says 0 => full message copied, | |
307 | + => partial message copied, | |
308 | - => error | |
309 | but does not say how to tell if connection closed remotely ??? */ | |
310 | if (result >= 0) | |
311 | result = databuf.len; /* actual num bytes copied */ | |
312 | else if (errno == EINTR) | |
313 | result = 0; /* our convention */ | |
314 | else { | |
315 | perror ("netsim: get sync msg: "); | |
316 | result = -1; | |
317 | } | |
318 | } else | |
319 | result = -1; | |
320 | ||
321 | } else /* _SWITCH */ { | |
322 | ||
323 | if (info[fd].implt == _SOCKET) { | |
324 | result = ipc_socket_read_pkt(fd, buf, maxlen, hdr, -1); | |
325 | } else if (info[fd].implt == _MMAP) { | |
326 | result = ipc_mmap_read_pkt(fd, buf, maxlen, NULL, -1); | |
327 | } else | |
328 | result = -1; | |
329 | } | |
330 | ||
331 | return result; | |
332 | } | |
333 | ||
334 | ||
335 | /* ------------------------------ simplified ---------------------------------- | |
336 | * result < 0 error, including connection closed, errno = EINTR (SIGUSR1) ??? | |
337 | * result = 0 ??? | |
338 | * result > 0 success, result bytes written | |
339 | */ | |
340 | int | |
341 | netsim_putmsg(int fd, char * buf, int len, swtchdr * hdr) | |
342 | { | |
343 | int result; | |
344 | ||
345 | errno = 0; | |
346 | ||
347 | if (info[fd].service == _SYNC) { | |
348 | ||
349 | if (info[fd].implt == _SOCKET) { | |
350 | /* ? write, ? fwrite, ? fputs, ? putmsg, ? ... */ | |
351 | int flags = 0; | |
352 | struct strbuf ctrlbuf; | |
353 | struct strbuf databuf; | |
354 | databuf.buf = buf; | |
355 | databuf.len = len; | |
356 | result = putmsg (fd, NULL/*ctrlbuf*/, &databuf, NULL/*flagsp*/); | |
357 | /* man says 0 => full message copied, | |
358 | - => error | |
359 | but does not say how to tell if connection closed remotely ??? */ | |
360 | if (result >= 0) | |
361 | result = databuf.len; /* actual num bytes copied */ | |
362 | else if (errno == EINTR) | |
363 | result = -1; /* our (confused!) convention */ | |
364 | else { | |
365 | perror ("netsim: put sync msg: "); | |
366 | result = -1; | |
367 | } | |
368 | } else | |
369 | result = -1; | |
370 | ||
371 | } else /* _SWITCH */ { | |
372 | ||
373 | if (info[fd].implt == _SOCKET) { | |
374 | result = ipc_socket_write_pkt(fd, buf, len, hdr); | |
375 | ||
376 | } else if (info[fd].implt == _MMAP) { | |
377 | result = ipc_mmap_write_pkt(fd, buf, len, hdr); | |
378 | ||
379 | } else if (info[fd].implt == _SNOOP){ | |
380 | struct strbuf data; | |
381 | data.buf = (char *) buf; | |
382 | data.maxlen = MAXDLBUF; | |
383 | data.len = len; | |
384 | result = putmsg(fd, NULL, &data, 0); | |
385 | if (result == 0) result = sizeof(hdr) + len; | |
386 | ||
387 | } else | |
388 | result = -1; | |
389 | } | |
390 | return result; | |
391 | } | |
392 | ||
393 | ||
394 | ||
395 | ||
396 | ||
397 | ||
398 | ||
399 | ||
400 | ||
401 | ||
402 | ||
403 | ||
404 | ||
405 | //////////////////////////////////////////////////////////////////////////////// | |
406 | // // | |
407 | // The following section is for Socket-based // | |
408 | // ^^^^^^ // | |
409 | //////////////////////////////////////////////////////////////////////////////// | |
410 | ||
411 | ||
412 | ||
413 | #define ETHER_ADDR_LEN 6 | |
414 | #define ETHER_HDR_LEN (6 + 6 + 2) | |
415 | ||
416 | #define SWITCH_PKT_HDR_SIZE 8 | |
417 | #define SWITCH_ETHERMTU (ETHERMTU + ETHER_HDR_LEN) | |
418 | #define MAX_SWITCH_PKT_SIZE (SWITCH_ETHERMTU + SWITCH_PKT_HDR_SIZE + sizeof(ushort_t)) | |
419 | ||
420 | ||
421 | ||
422 | ||
423 | /*note that timout==-1 means wait forever, which is the only value used... | |
424 | *change: returns 0 for socket closed at other end, PAL. | |
425 | */ | |
426 | static int | |
427 | read_all(int fd, char *buf, int len, int timout) | |
428 | { | |
429 | int result, saved_len; | |
430 | ||
431 | struct pollfd pfd; | |
432 | ||
433 | int index = 0; | |
434 | ||
435 | if (len == 0) | |
436 | return 0; | |
437 | ||
438 | saved_len = len; | |
439 | ||
440 | while (len > 0) { | |
441 | ||
442 | #if USE_POLL | |
443 | /* I can't see any reason for using poll here, either we wait in poll | |
444 | * or we wait in read, what's the difference...???... | |
445 | * its just going to cost more syscalls... | |
446 | */ | |
447 | pfd.fd = fd; | |
448 | pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; | |
449 | result = poll(&pfd, 1, timout); | |
450 | /* | |
451 | * poll results: | |
452 | * 0 => timeout (can't happen with -1 as the timeout value passed in) | |
453 | * >0 => number of `active' files in polling list | |
454 | * <0 => chech errno for {EAGAIN, EFAULT, EINTR, EINVAL} | |
455 | * | |
456 | * what the rest of simge wants: | |
457 | * 0 => socket closed (either from other end, indicated by zero-length | |
458 | * packet received, or from this end by the UI, | |
459 | * indicated by EINTR (SIGUSR1). | |
460 | * <0 => other error | |
461 | * >0 => that many bytes read | |
462 | */ | |
463 | if (result <= 0) { | |
464 | if (result < 0 && (errno == EINTR)) { | |
465 | return 0; /* this is the SIGUSR1 from our UI case, this thread | |
466 | * is being interrupted because the UI is closing | |
467 | * the socket from this end */ | |
468 | } else if (result == 0) { | |
469 | fprintf(stderr, "ERROR: read_all: poll(fd=%d) timedout \n", fd); | |
470 | return -1; | |
471 | } else { | |
472 | fprintf(stderr, "ERROR: read_all: poll: %s \n", strerror(errno)); | |
473 | return -1; | |
474 | } | |
475 | } | |
476 | assert(result == 1); | |
477 | ||
478 | #endif /* USE_POLL */ | |
479 | ||
480 | result = read(fd, &buf[index], len); | |
481 | if (result == len) { | |
482 | return saved_len; | |
483 | } | |
484 | if (result > 0) { | |
485 | index += result; | |
486 | len -= result; | |
487 | } else if (result < 0) { | |
488 | fprintf(stderr, "ERROR: read_all: read: %s \n", strerror(errno)); | |
489 | return -1; | |
490 | } else if (result == 0) { | |
491 | fprintf(stderr, "INFO: read_all: read: connection closed on the socket. \n"); | |
492 | return 0; /* | |
493 | * this is the "socket closed from the other end" case | |
494 | */ | |
495 | } | |
496 | } | |
497 | ||
498 | /* NOT REACHED */ | |
499 | ||
500 | return -1; | |
501 | } | |
502 | ||
503 | ||
504 | static int | |
505 | write_all(int fd, char *buf, int len) | |
506 | { | |
507 | int result; | |
508 | ||
509 | int index = 0; | |
510 | int saved_len = len; | |
511 | ||
512 | while (len > 0) { | |
513 | ||
514 | result = write(fd, &buf[index], len); | |
515 | if (result == len) | |
516 | return saved_len; | |
517 | ||
518 | if (result > 0) { | |
519 | index += result; | |
520 | len -= result; | |
521 | } else if (result < 0) { | |
522 | fprintf(stderr, "ERROR: write_all: write: %s \n", strerror(errno)); | |
523 | return -1; | |
524 | } else if (result == 0) { | |
525 | fprintf(stderr, "ERROR: write_all: write: returned 0 instead of writing %d bytes \n", len); | |
526 | return -1; | |
527 | } | |
528 | } | |
529 | ||
530 | /* NOT REACHED */ | |
531 | ||
532 | return -1; | |
533 | } | |
534 | ||
535 | ||
536 | /* | |
537 | * now returns (buf_len *PLUS* hdr_len) !!! PAL. | |
538 | * so that 0 can be the unambiguous indicator of socket closed at other end. | |
539 | * | |
540 | * on successful read store actual length read into hdr->pkt_len. PAL. | |
541 | */ | |
542 | static int | |
543 | ipc_socket_read_pkt(int fd, char *pkt, int maxlen, swtchdr *hdr, int timout) | |
544 | { | |
545 | int pktlen, result; | |
546 | swtchdr local_hdr, *hptr; | |
547 | ||
548 | if (hdr == NULL) | |
549 | hptr = &local_hdr; | |
550 | else | |
551 | hptr = hdr; | |
552 | ||
553 | result = read_all(fd, (char *) hptr, sizeof(swtchdr), timout); | |
554 | if (result <= 0) { /* was < 0), PAL*/ | |
555 | return result; | |
556 | } | |
557 | assert(result == sizeof(swtchdr)); | |
558 | ||
559 | pktlen = ntohl(hptr->pkt_len); /* real eth-packet len from switchsim hdr */ | |
560 | ||
561 | if (pktlen > maxlen) { | |
562 | fprintf(stderr, "ERROR: ipc_socket_read_pkt: pktlen %d > maxlen %d \n", | |
563 | pktlen, maxlen); | |
564 | return -1; | |
565 | } | |
566 | ||
567 | if (pktlen == 0) { | |
568 | hptr->pkt_len = pktlen; /*PAL*/ | |
569 | return pktlen + sizeof(swtchdr); /*was: pktlen; PAL*/ | |
570 | } | |
571 | ||
572 | if ((result = read_all(fd, pkt, pktlen, timout)) <= 0) { /*was: <0, PAL*/ | |
573 | return result; | |
574 | } | |
575 | assert(result == pktlen); | |
576 | ||
577 | hptr->pkt_len = pktlen; /*PAL*/ | |
578 | return pktlen + sizeof(swtchdr); /*was: pktlen; PAL*/ | |
579 | } | |
580 | ||
581 | /* | |
582 | * result = result-from-writev-syscall: | |
583 | * <0 error | |
584 | * =0 ? | |
585 | * >0 success, number of bytes written | |
586 | */ | |
587 | static int | |
588 | ipc_socket_write_pkt(int fd, char *pkt, int len, swtchdr *hdr) | |
589 | { | |
590 | int result; | |
591 | swtchdr *hptr, local_hdr; | |
592 | struct iovec wiovec[2]; | |
593 | ||
594 | if (hdr == NULL) { | |
595 | hptr = &local_hdr; | |
596 | hptr->pkt_type = htonl(PKT_DATA); | |
597 | } else { | |
598 | hptr = hdr; | |
599 | } | |
600 | ||
601 | hptr->pkt_len = htonl(len); | |
602 | ||
603 | wiovec[0].iov_base = (char *) hptr; | |
604 | wiovec[0].iov_len = sizeof(swtchdr); | |
605 | ||
606 | if (len == 0) { | |
607 | result = writev(fd, wiovec, 1); | |
608 | return result; | |
609 | } else { | |
610 | wiovec[1].iov_base = pkt; | |
611 | wiovec[1].iov_len = len; | |
612 | result = writev(fd, wiovec, 2); | |
613 | return result; | |
614 | } | |
615 | ||
616 | /* NOT REACHED */ | |
617 | return -1; | |
618 | } | |
619 | ||
620 | ||
621 | /* more swtchdr stuff -------------------------------------- */ | |
622 | ||
623 | ||
624 | ||
625 | ||
626 | typedef struct pkt_ctrl_ipc_type { | |
627 | int ipc_type; | |
628 | char *mmap_idstr; | |
629 | int mmap_file_size; | |
630 | } pkt_ctrl_ipc_type_t; | |
631 | ||
632 | ||
633 | ||
634 | typedef struct pkt_ctrl_key_type { | |
635 | int key_type; | |
636 | } pkt_ctrl_key_type_t; | |
637 | ||
638 | ||
639 | ||
640 | static int | |
641 | process_ack(int fd, int type) | |
642 | { | |
643 | int result; | |
644 | swtchdr hdr; | |
645 | ||
646 | char pkt[SWITCH_ETHERMTU]; | |
647 | ||
648 | result = ipc_socket_read_pkt(fd, pkt, SWITCH_ETHERMTU, &hdr, TIMEOUT_FIVE_SECOND); | |
649 | if (result <= 0) { /* was < 0, PAL*/ | |
650 | return -1; | |
651 | } | |
652 | ||
653 | switch (hdr.pkt_type) { | |
654 | case PKT_CTRL_VERSION_OK: | |
655 | case PKT_CTRL_IPC_TYPE_OK: | |
656 | case PKT_CTRL_KEY_TYPE_OK: | |
657 | case PKT_CTRL_INIT_END_OK: | |
658 | if (type == hdr.pkt_type) | |
659 | result = 0; | |
660 | else | |
661 | result = -1; | |
662 | break; | |
663 | case PKT_CTRL_ERROR: | |
664 | result = -1; | |
665 | break; | |
666 | default: | |
667 | result = -1; | |
668 | break; | |
669 | } | |
670 | ||
671 | return result; | |
672 | } | |
673 | ||
674 | ||
675 | static int | |
676 | process_version(int fd) | |
677 | { | |
678 | XDR xdr; | |
679 | char *ptr; | |
680 | union { | |
681 | char pkt[SWITCH_ETHERMTU]; | |
682 | uint64_t force_alignment; | |
683 | } aligned_pkt; | |
684 | swtchdr hdr; | |
685 | int len, result; | |
686 | ||
687 | ptr = (char *) SIMGE_SWITCH_VERSION; | |
688 | xdrmem_create(&xdr, aligned_pkt.pkt, SWITCH_ETHERMTU, XDR_ENCODE); | |
689 | result = xdr_string(&xdr, &ptr, 64); | |
690 | if (!result) { | |
691 | xdr_destroy(&xdr); | |
692 | return -1; | |
693 | } | |
694 | len = xdr_getpos(&xdr); | |
695 | xdr_destroy(&xdr); | |
696 | ||
697 | hdr.pkt_type = htonl(PKT_CTRL_VERSION); | |
698 | hdr.pkt_len = htonl(len); | |
699 | ||
700 | result = ipc_socket_write_pkt(fd, aligned_pkt.pkt, len, &hdr); | |
701 | if (result < 0) | |
702 | return result; | |
703 | ||
704 | result = process_ack(fd, PKT_CTRL_VERSION_OK); | |
705 | if (result < 0) { | |
706 | fprintf(stderr, "ERROR: libswitch: version %s not accepted by switch. \n", ptr); | |
707 | return -1; | |
708 | } | |
709 | ||
710 | return 0; | |
711 | } | |
712 | ||
713 | ||
714 | static int | |
715 | process_ipc_type(int fd, int ipc_type, char *mmap_idstr, int mmap_file_size) | |
716 | { | |
717 | int len; | |
718 | swtchdr hdr; | |
719 | XDR xdr; | |
720 | union { | |
721 | char pkt[SWITCH_ETHERMTU]; | |
722 | uint64_t force_alignment; | |
723 | } aligned_pkt; | |
724 | ||
725 | pkt_ctrl_ipc_type_t data; | |
726 | ||
727 | int result = 0; | |
728 | ||
729 | data.ipc_type = ipc_type; | |
730 | if (mmap_idstr == NULL) | |
731 | data.mmap_idstr = (char *) ""; | |
732 | else | |
733 | data.mmap_idstr = mmap_idstr; | |
734 | data.mmap_file_size = mmap_file_size; | |
735 | ||
736 | xdrmem_create(&xdr, aligned_pkt.pkt, SWITCH_ETHERMTU, XDR_ENCODE); | |
737 | result = xdr_int(&xdr, &data.ipc_type); | |
738 | if (!result) { | |
739 | xdr_destroy(&xdr); | |
740 | return -1; | |
741 | } | |
742 | result = xdr_string(&xdr, &data.mmap_idstr, MAXPATHLEN); | |
743 | if (!result) { | |
744 | xdr_destroy(&xdr); | |
745 | return -1; | |
746 | } | |
747 | result = xdr_int(&xdr, &data.mmap_file_size); | |
748 | if (!result) { | |
749 | xdr_destroy(&xdr); | |
750 | return -1; | |
751 | } | |
752 | len = xdr_getpos(&xdr); | |
753 | ||
754 | xdr_destroy(&xdr); | |
755 | ||
756 | hdr.pkt_type = htonl(PKT_CTRL_IPC_TYPE); | |
757 | hdr.pkt_len = htonl(len); | |
758 | ||
759 | result = ipc_socket_write_pkt(fd, aligned_pkt.pkt, len, &hdr); | |
760 | if (result < 0) | |
761 | return result; | |
762 | ||
763 | result = process_ack(fd, PKT_CTRL_IPC_TYPE_OK); | |
764 | if (result < 0) { | |
765 | fprintf(stderr, "ERROR: libswitch: ipc_type %d not accepted by switch. \n", ipc_type); | |
766 | } | |
767 | ||
768 | return 0; | |
769 | } | |
770 | ||
771 | ||
772 | static int | |
773 | process_key_type(int fd, int key_type) | |
774 | { | |
775 | int len; | |
776 | swtchdr hdr; | |
777 | XDR xdr; | |
778 | union { | |
779 | char pkt[SWITCH_ETHERMTU]; | |
780 | uint64_t force_alignment; | |
781 | } aligned_pkt; | |
782 | ||
783 | pkt_ctrl_key_type_t data; | |
784 | ||
785 | int result = 0; | |
786 | ||
787 | data.key_type = key_type; | |
788 | ||
789 | xdrmem_create(&xdr, aligned_pkt.pkt, SWITCH_ETHERMTU, XDR_ENCODE); | |
790 | result = xdr_int(&xdr, &data.key_type); | |
791 | if (!result) { | |
792 | xdr_destroy(&xdr); | |
793 | return -1; | |
794 | } | |
795 | len = xdr_getpos(&xdr); | |
796 | xdr_destroy(&xdr); | |
797 | ||
798 | hdr.pkt_type = htonl(PKT_CTRL_KEY_TYPE); | |
799 | hdr.pkt_len = htonl(len); | |
800 | ||
801 | result = ipc_socket_write_pkt(fd, aligned_pkt.pkt, len, &hdr); | |
802 | if (result < 0) | |
803 | return result; | |
804 | ||
805 | result = process_ack(fd, PKT_CTRL_KEY_TYPE_OK); | |
806 | if (result < 0) { | |
807 | fprintf(stderr, "ERROR: libswitch: key_type %d not accepted by switch. \n", key_type); | |
808 | return -1; | |
809 | } | |
810 | ||
811 | return 0; | |
812 | } | |
813 | ||
814 | ||
815 | static int | |
816 | process_init_end(int fd) | |
817 | { | |
818 | swtchdr hdr; | |
819 | ||
820 | int result = 0; | |
821 | ||
822 | hdr.pkt_type = htonl(PKT_CTRL_INIT_END); | |
823 | hdr.pkt_len = 0; | |
824 | ||
825 | result = ipc_socket_write_pkt(fd, NULL, 0, &hdr); | |
826 | if (result < 0) { | |
827 | return -1; | |
828 | } | |
829 | return 0; | |
830 | } | |
831 | ||
832 | ||
833 | ||
834 | static int | |
835 | switch_negotiate(int fd, int ipc_type, int key_type, char *mmap_idstr, int mmap_file_size) | |
836 | { | |
837 | int result; | |
838 | ||
839 | result = process_version(fd); | |
840 | if (result < 0) { | |
841 | return -1; | |
842 | } | |
843 | result = process_ipc_type(fd, ipc_type, mmap_idstr, mmap_file_size); | |
844 | if (result < 0) { | |
845 | return -1; | |
846 | } | |
847 | result = process_key_type(fd, key_type); | |
848 | if (result < 0) { | |
849 | return -1; | |
850 | } | |
851 | result = process_init_end(fd); | |
852 | if (result < 0) { | |
853 | return -1; | |
854 | } | |
855 | ||
856 | return 0; | |
857 | } | |
858 | ||
859 | ||
860 | ||
861 | ||
862 | /* | |
863 | * some more forward decls -------------------------------------------------- | |
864 | */ | |
865 | static void mmap_data_table_init(void); | |
866 | static int ipc_create_mmap_files(const char *mmap_dir, char *mmap_idstr, int mmap_file_size); | |
867 | int mmap_data_table_initialized = 0; | |
868 | ||
869 | ||
870 | ||
871 | ||
872 | ||
873 | ||
874 | /* | |
875 | * the old "make a connection" (either socket or mmap) function | |
876 | * | |
877 | * returns the socket fd on success, -1 otherwise. | |
878 | */ | |
879 | int | |
880 | ipc_init(const char *switch_server, const char *ipc_type_string, int key_type, const char *mmap_dir, int mmap_file_size) | |
881 | { | |
882 | int mmap_fd, ipc_type, result; | |
883 | int sockfd, server_port; | |
884 | ||
885 | struct hostent *server; | |
886 | struct sockaddr_in serv_addr; | |
887 | struct utsname host_utsname; | |
888 | ||
889 | const char *server_name; | |
890 | ||
891 | char mmap_idstr[MAXPATHLEN]; | |
892 | ||
893 | ||
894 | if (strcmp(ipc_type_string, "socket") == 0) { | |
895 | ipc_type = PKT_CTRL_IPC_SOCKET; | |
896 | } else if (strcmp(ipc_type_string, "mmap") == 0) { | |
897 | ipc_type = PKT_CTRL_IPC_MMAP; | |
898 | } else if (strcmp(ipc_type_string, "") == 0) { | |
899 | ipc_type = PKT_CTRL_IPC_SOCKET; | |
900 | } else { | |
901 | fprintf(stderr, "ERROR: libswitch: unknown switch ipc type specified: %s \n", ipc_type_string); | |
902 | return -1; | |
903 | } | |
904 | ||
905 | if (uname(&host_utsname) == -1) { | |
906 | fprintf(stderr, "ERROR: libswitch: uname: %s \n", strerror(errno)); | |
907 | return -1; | |
908 | } | |
909 | ||
910 | server_name = host_utsname.nodename; | |
911 | ||
912 | /* TBD: System with multiple interfaces with different hostnames */ | |
913 | ||
914 | if (switch_server != NULL) { | |
915 | if (strcmp(switch_server, server_name) != 0) { | |
916 | if (ipc_type == PKT_CTRL_IPC_MMAP) { | |
917 | fprintf(stderr, "ERROR:libswitch: mmap can't be used for ipc " | |
918 | "between the machines %s and %s \n", | |
919 | switch_server, server_name); | |
920 | return -1; | |
921 | } | |
922 | server_name = switch_server; | |
923 | } | |
924 | } | |
925 | ||
926 | sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
927 | if (sockfd < 0) { | |
928 | fprintf(stderr, "ERROR: libswitch: socket: %s \n", strerror(errno)); | |
929 | return -1; | |
930 | } | |
931 | ||
932 | server = gethostbyname(server_name); | |
933 | if (server == NULL) { | |
934 | fprintf(stderr, "ERROR: libswitch: gethostbyname: %s \n", strerror(h_errno)); | |
935 | close(sockfd); | |
936 | return -1; | |
937 | } | |
938 | ||
939 | server_port = SWITCH_DEFAULT_PORT; | |
940 | ||
941 | bzero((char *) &serv_addr, sizeof(struct sockaddr_in)); | |
942 | serv_addr.sin_family = AF_INET; | |
943 | bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); | |
944 | serv_addr.sin_port = htons(server_port); | |
945 | ||
946 | if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { | |
947 | fprintf(stderr, "ERROR: libswitch: connect: %s \n", strerror(errno)); | |
948 | close(sockfd); | |
949 | return -1; | |
950 | } | |
951 | ||
952 | if (ipc_type == PKT_CTRL_IPC_MMAP) { | |
953 | if (mmap_data_table_initialized == 0) | |
954 | mmap_data_table_init(); | |
955 | mmap_fd = ipc_create_mmap_files(mmap_dir, mmap_idstr, mmap_file_size); | |
956 | if (mmap_fd < 0) { | |
957 | fprintf(stderr, "ERROR: libswitch: failed to create mmap files for ipc \n"); | |
958 | close(sockfd); | |
959 | return -1; | |
960 | } | |
961 | } | |
962 | ||
963 | result = switch_negotiate(sockfd, ipc_type, key_type, mmap_idstr, mmap_file_size); | |
964 | if (result < 0) { | |
965 | fprintf(stderr, "ERROR: libswitch: negotiation with switch server %s failed. \n", server_name); | |
966 | close(sockfd); | |
967 | return result; | |
968 | } | |
969 | ||
970 | if (ipc_type == PKT_CTRL_IPC_MMAP) { | |
971 | close(sockfd); | |
972 | info[ mmap_fd ].implt = _MMAP; | |
973 | result = mmap_fd; | |
974 | } else { | |
975 | info[ sockfd ].implt = _SOCKET; | |
976 | result = sockfd; | |
977 | } | |
978 | ||
979 | return result; | |
980 | } | |
981 | ||
982 | ||
983 | ||
984 | ||
985 | ||
986 | ||
987 | ||
988 | //////////////////////////////////////////////////////////////////////////////// | |
989 | // // | |
990 | // The following is for Mmap-based blaze networking... // | |
991 | // ^^^^ // | |
992 | //////////////////////////////////////////////////////////////////////////////// | |
993 | ||
994 | ||
995 | ||
996 | ||
997 | #define FIRST_MMAP_FD 1000 | |
998 | ||
999 | #define MMAP_DATA_TABLE_SIZE 32 | |
1000 | ||
1001 | typedef struct mmap_data { | |
1002 | ||
1003 | int fd; | |
1004 | ||
1005 | char *snd_mmap_addr; | |
1006 | int snd_mmap_index; | |
1007 | int snd_mmap_size; | |
1008 | ||
1009 | char *rcv_mmap_addr; | |
1010 | int rcv_mmap_index; | |
1011 | int rcv_mmap_size; | |
1012 | ||
1013 | } mmap_data_t; | |
1014 | ||
1015 | mmap_data_t mmap_data_table[MMAP_DATA_TABLE_SIZE]; | |
1016 | ||
1017 | int mmap_data_table_index; | |
1018 | /*int mmap_data_table_initialized; is moved up above */ | |
1019 | mutex_t mmap_data_table_lock; | |
1020 | ||
1021 | static void | |
1022 | mmap_data_table_init(void) | |
1023 | { | |
1024 | int index; | |
1025 | ||
1026 | mutex_init(&mmap_data_table_lock, USYNC_THREAD, NULL); | |
1027 | ||
1028 | for (index=0; index<MMAP_DATA_TABLE_SIZE; index++) { | |
1029 | mmap_data_table[index].fd = -1; | |
1030 | } | |
1031 | ||
1032 | mmap_data_table_initialized = 1; | |
1033 | ||
1034 | return; | |
1035 | } | |
1036 | ||
1037 | static mmap_data_t * | |
1038 | mmap_data_alloc(void) | |
1039 | { | |
1040 | int index; | |
1041 | ||
1042 | int found = 0; | |
1043 | ||
1044 | mutex_lock(&mmap_data_table_lock); | |
1045 | for (index=0; index<MMAP_DATA_TABLE_SIZE; index++) { | |
1046 | if (mmap_data_table[index].fd == -1) { | |
1047 | mmap_data_table[index].fd = index + FIRST_MMAP_FD; | |
1048 | found = 1; | |
1049 | break; | |
1050 | } | |
1051 | } | |
1052 | mutex_unlock(&mmap_data_table_lock); | |
1053 | ||
1054 | if (found == 0) | |
1055 | return NULL; | |
1056 | ||
1057 | return &mmap_data_table[index]; | |
1058 | } | |
1059 | ||
1060 | #define SWITCH_LIB_PAGE_SIZE 8192 | |
1061 | ||
1062 | static int | |
1063 | ipc_mmap_init_file(int fd, int mmap_file_size) | |
1064 | { | |
1065 | char *buf; | |
1066 | int index, page_count, count; | |
1067 | ||
1068 | int result = 0; | |
1069 | ||
1070 | page_count = mmap_file_size / SWITCH_LIB_PAGE_SIZE; | |
1071 | ||
1072 | buf = (char *) calloc(1, SWITCH_LIB_PAGE_SIZE); | |
1073 | if (buf == NULL) { | |
1074 | fprintf(stderr, "ERROR: libswitch: calloc SWITCH_LIB_PAGE_SIZE returned NULL \n"); | |
1075 | return -1; | |
1076 | } | |
1077 | for (index=0; index<page_count; index++) { | |
1078 | result = write(fd, buf, SWITCH_LIB_PAGE_SIZE); | |
1079 | if (result < 0) { | |
1080 | fprintf(stderr, "ERROR: libswitch: failed to initialize mmap file : %s \n", strerror(errno)); | |
1081 | return -1; | |
1082 | } | |
1083 | } | |
1084 | ||
1085 | count = mmap_file_size % SWITCH_LIB_PAGE_SIZE; | |
1086 | for (index=0; index<count; index++) { | |
1087 | result = write(fd, buf, count); | |
1088 | if (result < 0) { | |
1089 | fprintf(stderr, "ERROR: libswitch: failed to initialize mmap file : %s \n", strerror(errno)); | |
1090 | return -1; | |
1091 | } | |
1092 | } | |
1093 | ||
1094 | free(buf); | |
1095 | ||
1096 | return 0; | |
1097 | } | |
1098 | ||
1099 | static int | |
1100 | ipc_create_mmap_files(const char *mmap_dir, char *mmap_idstr, int mmap_file_size) | |
1101 | { | |
1102 | int fd, result; | |
1103 | pid_t pid; | |
1104 | caddr_t addr; | |
1105 | char send_filename[MAXPATHLEN]; | |
1106 | char recv_filename[MAXPATHLEN]; | |
1107 | ||
1108 | mmap_data_t *mdp; | |
1109 | ||
1110 | pid = getpid(); | |
1111 | ||
1112 | mdp = mmap_data_alloc(); | |
1113 | if (mdp == NULL) { | |
1114 | fprintf(stderr, "ERROR: libswitch: ran out of mmap ipc file descriptors. \n"); | |
1115 | return -1; | |
1116 | } | |
1117 | ||
1118 | if (mmap_dir == NULL) { | |
1119 | strcpy(send_filename, "/tmp/SAM/send_to_switch."); | |
1120 | } else { | |
1121 | strcpy(send_filename, mmap_dir); | |
1122 | strcat(send_filename, "/send_to_switch."); | |
1123 | } | |
1124 | sprintf(mmap_idstr, "%d_%d", getpid(), mdp->fd); | |
1125 | strcat(send_filename, mmap_idstr); | |
1126 | ||
1127 | fd = open(send_filename, O_RDWR|O_CREAT|O_TRUNC, 0777); | |
1128 | if (fd == -1) { | |
1129 | fprintf(stderr, "ERROR: libswitch: open: ( filename %s ) %s \n", send_filename, strerror(errno)); | |
1130 | return -1; | |
1131 | } | |
1132 | ||
1133 | fchmod(fd, 0777); | |
1134 | ||
1135 | result = ipc_mmap_init_file(fd, mmap_file_size); | |
1136 | if (result < 0) { | |
1137 | close(fd); | |
1138 | unlink(send_filename); | |
1139 | return -1; | |
1140 | } | |
1141 | ||
1142 | addr = NULL; | |
1143 | ||
1144 | addr = mmap(addr, mmap_file_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
1145 | if (addr == (caddr_t ) -1) { | |
1146 | close(fd); | |
1147 | unlink(send_filename); | |
1148 | fprintf(stderr, "ERROR: libswitch: mmap(%s): %s \n", send_filename, strerror(errno)); | |
1149 | return -1; | |
1150 | } | |
1151 | ||
1152 | mdp->snd_mmap_addr = (char *) addr; | |
1153 | mdp->snd_mmap_size = mmap_file_size; | |
1154 | mdp->snd_mmap_index = 0; | |
1155 | close(fd); | |
1156 | ||
1157 | if (mmap_dir == NULL) { | |
1158 | strcpy(recv_filename, "/tmp/SAM/recv_from_switch."); | |
1159 | } else { | |
1160 | strcpy(recv_filename, mmap_dir); | |
1161 | strcat(recv_filename, "/recv_from_switch."); | |
1162 | } | |
1163 | strcat(recv_filename, mmap_idstr); | |
1164 | ||
1165 | fd = open(recv_filename, O_RDWR|O_CREAT|O_TRUNC, 0777); | |
1166 | if (fd == -1) { | |
1167 | munmap(mdp->snd_mmap_addr, mmap_file_size); | |
1168 | unlink(send_filename); | |
1169 | fprintf(stderr, "ERROR: libswitch: open: ( filename %s ) %s \n", recv_filename, strerror(errno)); | |
1170 | return -1; | |
1171 | } | |
1172 | ||
1173 | fchmod(fd, 0777); | |
1174 | ||
1175 | result = ipc_mmap_init_file(fd, mmap_file_size); | |
1176 | if (result < 0) { | |
1177 | close(fd); | |
1178 | unlink(recv_filename); | |
1179 | munmap(mdp->snd_mmap_addr, mmap_file_size); | |
1180 | unlink(send_filename); | |
1181 | return -1; | |
1182 | } | |
1183 | ||
1184 | addr = NULL; | |
1185 | ||
1186 | addr = mmap(addr, mmap_file_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
1187 | if (addr == (caddr_t ) -1) { | |
1188 | close(fd); | |
1189 | unlink(recv_filename); | |
1190 | unlink(send_filename); | |
1191 | munmap(mdp->snd_mmap_addr, mmap_file_size); | |
1192 | fprintf(stderr, "ERROR: libswitch: mmap(%s): %s \n", recv_filename, strerror(errno)); | |
1193 | return -1; | |
1194 | } | |
1195 | ||
1196 | mdp->rcv_mmap_addr = (char *) addr; | |
1197 | mdp->rcv_mmap_size = mmap_file_size; | |
1198 | mdp->rcv_mmap_index = 0; | |
1199 | close(fd); | |
1200 | ||
1201 | return mdp->fd; | |
1202 | } | |
1203 | ||
1204 | ||
1205 | #define MMAP_PKT_OFFSET SWITCH_PKT_HDR_SIZE | |
1206 | #define MMAP_CLOSE -1 | |
1207 | ||
1208 | ||
1209 | static int | |
1210 | ipc_mmap_read_pkt(int fd, char *pkt, int maxlen, swtchdr *hdr, int timout) | |
1211 | { | |
1212 | int pktlen; | |
1213 | swtchdr *hptr; | |
1214 | ||
1215 | char *src; | |
1216 | mmap_data_t *mdp; | |
1217 | ||
1218 | ||
1219 | if (0) { | |
1220 | fprintf(stderr, "INFO: ipc_mmap_read_pkt called with timout %d \n", timout); | |
1221 | } | |
1222 | ||
1223 | if ((fd - FIRST_MMAP_FD) >= MMAP_DATA_TABLE_SIZE) | |
1224 | return -1; | |
1225 | ||
1226 | mdp = &mmap_data_table[fd - FIRST_MMAP_FD]; | |
1227 | ||
1228 | hptr = (swtchdr *) (mdp->rcv_mmap_addr + mdp->rcv_mmap_index); | |
1229 | for (;;) { | |
1230 | pktlen = hptr->pkt_len; | |
1231 | if (pktlen != 0) { | |
1232 | pktlen = ntohl(pktlen); | |
1233 | if (pktlen == MMAP_CLOSE) { | |
1234 | return -1; | |
1235 | } else { | |
1236 | if (hdr != NULL) { | |
1237 | hdr->pkt_type = ntohl(hptr->pkt_type); | |
1238 | hdr->pkt_len = pktlen; | |
1239 | } | |
1240 | ||
1241 | if (pktlen > maxlen) { | |
1242 | fprintf(stderr, "ERROR: libswitch: ipc_mmap_read_pkt: pktlen %d > maxlen %d \n", pktlen, maxlen); | |
1243 | return -1; | |
1244 | } | |
1245 | ||
1246 | src = (mdp->rcv_mmap_addr + mdp->rcv_mmap_index) + MMAP_PKT_OFFSET; | |
1247 | ||
1248 | bcopy(src, pkt, pktlen); | |
1249 | ||
1250 | mdp->rcv_mmap_index += MAX_SWITCH_PKT_SIZE; | |
1251 | ||
1252 | if ((mdp->rcv_mmap_index + MAX_SWITCH_PKT_SIZE) > mdp->rcv_mmap_size) { | |
1253 | mdp->rcv_mmap_index = 0; | |
1254 | } | |
1255 | ||
1256 | hptr->pkt_len = 0; | |
1257 | return pktlen; | |
1258 | } | |
1259 | } | |
1260 | } | |
1261 | ||
1262 | /* NOT REACHED */ | |
1263 | } | |
1264 | ||
1265 | ||
1266 | static int | |
1267 | ipc_mmap_write_pkt(int fd, char *pkt, int pktlen, swtchdr *hdr) | |
1268 | { | |
1269 | char *dst; | |
1270 | mmap_data_t *mdp; | |
1271 | swtchdr *hptr; | |
1272 | ||
1273 | if (pktlen > SWITCH_ETHERMTU) { | |
1274 | fprintf(stderr, "ERROR: libswitch: ipc_mmap_write_pkt: pktlen %d > maxlen %d \n", pktlen, SWITCH_ETHERMTU); | |
1275 | return -1; | |
1276 | } | |
1277 | ||
1278 | if ((fd - FIRST_MMAP_FD) >= MMAP_DATA_TABLE_SIZE) | |
1279 | return -1; | |
1280 | ||
1281 | mdp = &mmap_data_table[fd - FIRST_MMAP_FD]; | |
1282 | ||
1283 | hptr = (swtchdr *) (mdp->snd_mmap_addr + mdp->snd_mmap_index); | |
1284 | if (hdr == NULL) { | |
1285 | hptr->pkt_type = htonl(PKT_DATA); | |
1286 | } else { | |
1287 | hptr->pkt_type = htonl(hdr->pkt_type); | |
1288 | } | |
1289 | ||
1290 | dst = (mdp->snd_mmap_addr + mdp->snd_mmap_index) + MMAP_PKT_OFFSET; | |
1291 | ||
1292 | bcopy(pkt, dst, pktlen); | |
1293 | ||
1294 | mdp->snd_mmap_index += MAX_SWITCH_PKT_SIZE; | |
1295 | ||
1296 | if ((mdp->snd_mmap_index + MAX_SWITCH_PKT_SIZE) > mdp->snd_mmap_size) { | |
1297 | mdp->snd_mmap_index = 0; | |
1298 | } | |
1299 | ||
1300 | hptr->pkt_len = htonl(pktlen); | |
1301 | ||
1302 | return pktlen; | |
1303 | } | |
1304 | ||
1305 | ||
1306 | ||
1307 | ||
1308 | ||
1309 | ||
1310 | ||
1311 | ||
1312 | ||
1313 | ||
1314 | //////////////////////////////////////////////////////////////////////////////// | |
1315 | // // | |
1316 | // The following section is for Snoop-based blaze networking... // | |
1317 | // ^^^^^ // | |
1318 | //////////////////////////////////////////////////////////////////////////////// | |
1319 | ||
1320 | ||
1321 | ||
1322 | ||
1323 | /*#include <dlpi.h> is up above */ | |
1324 | ||
1325 | /* usage: | |
1326 | * fd = init_snoop_device ("ge", 1); <--- implemented here, this is | |
1327 | * the only non-static ftn. | |
1328 | * getmsg (fd,... <--- std Solaris syscall | |
1329 | * putmsg (fd,... <--- std Solaris syscall | |
1330 | * close (fd) | |
1331 | */ | |
1332 | ||
1333 | /* forward decls for this section ------------------------------------ | |
1334 | */ | |
1335 | static int snoop_dlattachreq(int fd, ulong_t ppa); | |
1336 | static int snoop_dlokack(int fd, char *bufp); | |
1337 | static int snoop_dlpromisconreq(int fd, ulong_t level); | |
1338 | static int snoop_dlbindreq(int fd, ulong_t sap, ulong_t max_conind, | |
1339 | ulong_t service_mode, ulong_t conn_mgmt, ulong_t xidtest); | |
1340 | static int snoop_dlbindack(int fd, char *bufp); | |
1341 | static int snoop_strioctl(int fd, int cmd, int timout, int len, char *dp); | |
1342 | static int snoop_strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, | |
1343 | int *flagsp, const char *caller); | |
1344 | static int snoop_expecting (int prim, union DL_primitives *dlp); | |
1345 | static const char * snoop_dlprim(ulong_t prim); | |
1346 | ||
1347 | ||
1348 | #if 0 /* | |
1349 | * Someday we may have to resurrect this, or maybe we'll get lucky... | |
1350 | * Here is the code that used to be in "main.cc" for parsing the | |
1351 | * "-N 0=ge0,1=ge0" host device snooping specifications. That | |
1352 | * string, without the -N, is now accessable through the function | |
1353 | * call SYSTEM_get_hostconfig ("snoop.args"); | |
1354 | */ | |
1355 | int num_matches; | |
1356 | int nic0, nic1, minor0, minor1; | |
1357 | char devname0[32+4]; | |
1358 | char devname1[32+4]; | |
1359 | char devbuf[64]; | |
1360 | char *arg, comma; | |
1361 | ||
1362 | if (argndx == argc) { | |
1363 | fprintf(stderr, "ERROR: No argument specified to -N \n"); | |
1364 | exit(4); | |
1365 | } | |
1366 | ||
1367 | arg = argv[argndx++]; | |
1368 | ||
1369 | nic0 = minor0 = nic1 = minor1 = 0; | |
1370 | ||
1371 | num_matches = sscanf(arg, "%d=%32[a-zA-Z]%d%c%d=%32[a-zA-Z]%d", | |
1372 | &nic0, devname0, &minor0, &comma, &nic1, devname1, &minor1); | |
1373 | ||
1374 | ||
1375 | if ( (num_matches != 3) && (num_matches != 7) ) { | |
1376 | switch (num_matches) { | |
1377 | case 0: | |
1378 | case 4: | |
1379 | fprintf(stderr, "ERROR: Bad argument (%s) to -N \n", arg); | |
1380 | break; | |
1381 | ||
1382 | case 1: | |
1383 | case 5: | |
1384 | fprintf(stderr, "ERROR: Bad argument (%s) to -N. <digit>=<string><digit> expected. \n", arg); | |
1385 | break; | |
1386 | ||
1387 | case 2: | |
1388 | case 6: | |
1389 | fprintf(stderr, "ERROR: Bad argument (%s) to -N. device minor number incorrectly specified.\n", arg); | |
1390 | break; | |
1391 | ||
1392 | default: | |
1393 | fprintf(stderr, "ERROR: Bad argument (%s) to -N \n", arg); | |
1394 | break; | |
1395 | } | |
1396 | ||
1397 | exit(4); | |
1398 | } | |
1399 | ||
1400 | if (num_matches > 3) { | |
1401 | if (comma != ',') { | |
1402 | fprintf(stdout, "WARNING: Processing -N argument: comma expected between multiple snoop device specification.\n"); | |
1403 | } | |
1404 | } | |
1405 | ||
1406 | if (nic0 >= NUM_SIMGE) { | |
1407 | fprintf(stderr, "ERROR: Bad GE NIC number ( %d ) specified. allowed range 0 to %d \n", nic0, (NUM_SIMGE-1)); | |
1408 | exit(4); | |
1409 | } | |
1410 | ||
1411 | if (num_matches > 4) { | |
1412 | if (nic1 >= NUM_SIMGE) { | |
1413 | fprintf(stderr, "ERROR: Bad GE NIC number ( %d ) specified. allowed range 0 to %d \n", nic1, (NUM_SIMGE-1)); | |
1414 | exit(4); | |
1415 | } | |
1416 | } | |
1417 | ||
1418 | ||
1419 | devbuf[0] = 0; | |
1420 | strcat(devbuf, "/dev/"); | |
1421 | strcat(devbuf, devname0); | |
1422 | network_device_to_snoop[nic0] = strdup(devbuf); | |
1423 | if (network_device_to_snoop[nic0] == NULL) { | |
1424 | fprintf(stderr, "ERROR: Ran out of memory while duplicating string %s. \n", devbuf); | |
1425 | exit(4); | |
1426 | } | |
1427 | network_device_minor_num[nic0] = minor0; | |
1428 | ||
1429 | fprintf(stdout, "Will snoop device %s%d for NIC ge%d \n", network_device_to_snoop[nic0], minor0, nic0); | |
1430 | ||
1431 | if (num_matches == 7) { | |
1432 | devbuf[0] = 0; | |
1433 | strcat(devbuf, "/dev/"); | |
1434 | strcat(devbuf, devname1); | |
1435 | network_device_to_snoop[nic1] = strdup(devbuf); | |
1436 | if (network_device_to_snoop[nic1] == NULL) { | |
1437 | fprintf(stderr, "ERROR: Ran out of memory while duplicating string %s. \n", devbuf); | |
1438 | exit(4); | |
1439 | } | |
1440 | network_device_minor_num[nic1] = minor1; | |
1441 | ||
1442 | fprintf(stdout, "Will snoop device %s%d for NIC ge%d \n", network_device_to_snoop[nic1], minor1, nic1); | |
1443 | } | |
1444 | #endif | |
1445 | ||
1446 | ||
1447 | ||
1448 | /* | |
1449 | * inputs: name is eg "ce", minor is eg 1, to snoop physical device "ce1". | |
1450 | * returns filedescr, or -1 on error | |
1451 | */ | |
1452 | int init_snoop_device(const char * name, int minor) | |
1453 | { | |
1454 | int fd; | |
1455 | char buf[MAXDLBUF]; | |
1456 | ||
1457 | /* Open the device */ | |
1458 | ||
1459 | if ((fd = open(name, O_RDWR)) < 0) { | |
1460 | printf("FYI: Unable to snoop \"%s\" (try runing as root?)\n", name); | |
1461 | return -1; | |
1462 | } | |
1463 | ||
1464 | ||
1465 | /* Attach */ | |
1466 | ||
1467 | if (snoop_dlattachreq(fd, minor) < 0) goto nogood; | |
1468 | if (snoop_dlokack(fd, buf) < 0) goto nogood; | |
1469 | ||
1470 | /* pick up everything on the wire */ | |
1471 | ||
1472 | #if 0 | |
1473 | if (snoop_dlpromisconreq(fd, DL_PROMISC_PHYS) < 0) goto nogood; | |
1474 | #endif | |
1475 | ||
1476 | if (snoop_dlpromisconreq(fd, DL_PROMISC_SAP) < 0) goto nogood; | |
1477 | if (snoop_dlokack(fd, buf) < 0) goto nogood; | |
1478 | ||
1479 | /* Bind: use 2 as sap for token ring and 0 for else */ | |
1480 | ||
1481 | if (snoop_dlbindreq(fd, 0, 0, DL_CLDLS, 0, 0) < 0) goto nogood; | |
1482 | if (snoop_dlbindack(fd, buf) < 0) goto nogood; | |
1483 | ||
1484 | if (snoop_strioctl(fd, DLIOCRAW, -1, 0, (char *) NULL) < 0) { | |
1485 | perror("init_snoop_device: DLIOCRAW"); | |
1486 | goto nogood; | |
1487 | } | |
1488 | ||
1489 | /* Flush the read side of the Stream */ | |
1490 | ||
1491 | if (ioctl(fd, I_FLUSH, FLUSHR) < 0) { | |
1492 | perror("init_snoop_device: I_FLUSH"); | |
1493 | goto nogood; | |
1494 | } | |
1495 | ||
1496 | good: | |
1497 | #if 0 | |
1498 | { | |
1499 | char hostname[256]; | |
1500 | struct hostent *hp; | |
1501 | uint_t host_ipaddr; | |
1502 | /* get host ipaddr for filtering */ | |
1503 | /* this looks bogus, what if the host machine has multiple NICs... */ | |
1504 | gethostname(hostname, sizeof (hostname)); | |
1505 | if ((hp = gethostbyname(hostname)) == NULL) { | |
1506 | perror("gethostbyname error\n"); | |
1507 | return; | |
1508 | } | |
1509 | *** this needs to be saved (for use by getmsg) in the info[fd] array *** | |
1510 | host_ipaddr = *(uint_t *) hp->h_addr; | |
1511 | } | |
1512 | #endif | |
1513 | return fd; | |
1514 | ||
1515 | nogood: | |
1516 | close (fd); | |
1517 | return -1; | |
1518 | } | |
1519 | ||
1520 | ||
1521 | int snoop_getmsg (int fd, char * buf, int maxlen) | |
1522 | { | |
1523 | return -1; | |
1524 | } | |
1525 | ||
1526 | int snoop_putmsg (int fd, char * buf, int len) | |
1527 | { | |
1528 | return -1; | |
1529 | } | |
1530 | ||
1531 | ||
1532 | /* dlpi routines */ | |
1533 | ||
1534 | static int | |
1535 | snoop_dlattachreq(int fd, ulong_t ppa) | |
1536 | { | |
1537 | dl_attach_req_t attach_req; | |
1538 | int flags; | |
1539 | struct strbuf ctl; | |
1540 | ||
1541 | attach_req.dl_primitive = DL_ATTACH_REQ; | |
1542 | attach_req.dl_ppa = ppa; | |
1543 | ||
1544 | ctl.maxlen = 0; | |
1545 | ctl.len = sizeof(attach_req); | |
1546 | ctl.buf = (char *) &attach_req; | |
1547 | ||
1548 | flags = 0; | |
1549 | ||
1550 | if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { | |
1551 | perror("dlattachreq: putmsg"); | |
1552 | return -1; | |
1553 | } | |
1554 | ||
1555 | return 0; | |
1556 | } | |
1557 | ||
1558 | ||
1559 | static int | |
1560 | snoop_dlokack(int fd, char *bufp) | |
1561 | { | |
1562 | int flags; | |
1563 | struct strbuf ctl; | |
1564 | union DL_primitives *dlp; | |
1565 | ||
1566 | ctl.maxlen = MAXDLBUF; | |
1567 | ctl.len = 0; | |
1568 | ctl.buf = bufp; | |
1569 | ||
1570 | if (snoop_strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack") | |
1571 | < 0) | |
1572 | return -1; | |
1573 | ||
1574 | dlp = (union DL_primitives *) ctl.buf; | |
1575 | ||
1576 | if (snoop_expecting(DL_OK_ACK, dlp) < 0) | |
1577 | return -1; | |
1578 | ||
1579 | if (ctl.len < sizeof(dl_ok_ack_t)) { | |
1580 | vargs_error(0, "snoop_dlokack: response len too short: %d", ctl.len); | |
1581 | return -1; | |
1582 | } | |
1583 | ||
1584 | if (flags != RS_HIPRI) { | |
1585 | vargs_error(0, "snoop_dlokack: DL_OK_ACK was not M_PCPROTO"); | |
1586 | return -1; | |
1587 | } | |
1588 | ||
1589 | return 0; | |
1590 | } | |
1591 | ||
1592 | ||
1593 | static int | |
1594 | snoop_dlpromisconreq(int fd, ulong_t level) | |
1595 | { | |
1596 | dl_promiscon_req_t promiscon_req; | |
1597 | int flags; | |
1598 | struct strbuf ctl; | |
1599 | ||
1600 | promiscon_req.dl_primitive = DL_PROMISCON_REQ; | |
1601 | promiscon_req.dl_level = level; | |
1602 | ||
1603 | ctl.maxlen = 0; | |
1604 | ctl.len = sizeof(promiscon_req); | |
1605 | ctl.buf = (char *) &promiscon_req; | |
1606 | ||
1607 | flags = 0; | |
1608 | ||
1609 | if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { | |
1610 | vargs_error(0, "snoop_dlpromisconreq: putmsg"); | |
1611 | return -1; | |
1612 | } | |
1613 | ||
1614 | return 0; | |
1615 | } | |
1616 | ||
1617 | ||
1618 | void | |
1619 | snoop_dlpromiscoff(int fd, ulong_t level) | |
1620 | { | |
1621 | dl_promiscoff_req_t promiscoff_req; | |
1622 | struct strbuf ctl; | |
1623 | int flags; | |
1624 | ||
1625 | promiscoff_req.dl_primitive = DL_PROMISCOFF_REQ; | |
1626 | promiscoff_req.dl_level = level; | |
1627 | ||
1628 | ctl.maxlen = 0; | |
1629 | ctl.len = sizeof (promiscoff_req); | |
1630 | ctl.buf = (char *) &promiscoff_req; | |
1631 | ||
1632 | flags = 0; | |
1633 | ||
1634 | if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) | |
1635 | vargs_error(0, "dlpromiscoff: putmsg"); | |
1636 | ||
1637 | return; | |
1638 | } | |
1639 | ||
1640 | ||
1641 | static int | |
1642 | snoop_dlbindreq(int fd, | |
1643 | ulong_t sap, | |
1644 | ulong_t max_conind, | |
1645 | ulong_t service_mode, | |
1646 | ulong_t conn_mgmt, | |
1647 | ulong_t xidtest) | |
1648 | { | |
1649 | dl_bind_req_t bind_req; | |
1650 | int flags; | |
1651 | struct strbuf ctl; | |
1652 | ||
1653 | bind_req.dl_primitive = DL_BIND_REQ; | |
1654 | bind_req.dl_sap = sap; | |
1655 | bind_req.dl_max_conind = max_conind; | |
1656 | bind_req.dl_service_mode = service_mode; | |
1657 | bind_req.dl_conn_mgmt = conn_mgmt; | |
1658 | bind_req.dl_xidtest_flg = xidtest; | |
1659 | ||
1660 | ctl.maxlen = 0; | |
1661 | ctl.len = sizeof (bind_req); | |
1662 | ctl.buf = (char *) &bind_req; | |
1663 | ||
1664 | flags = 0; | |
1665 | ||
1666 | if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { | |
1667 | perror("snoop_dlbindreq: putmsg"); | |
1668 | return -1; | |
1669 | } | |
1670 | ||
1671 | return 0; | |
1672 | } | |
1673 | ||
1674 | ||
1675 | static int | |
1676 | snoop_dlbindack(int fd, char *bufp) | |
1677 | { | |
1678 | int flags; | |
1679 | struct strbuf ctl; | |
1680 | union DL_primitives *dlp; | |
1681 | ||
1682 | ctl.maxlen = MAXDLBUF; | |
1683 | ctl.len = 0; | |
1684 | ctl.buf = bufp; | |
1685 | ||
1686 | if (snoop_strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack") | |
1687 | < 0) | |
1688 | return -1; | |
1689 | ||
1690 | dlp = (union DL_primitives *) ctl.buf; | |
1691 | ||
1692 | if (snoop_expecting(DL_BIND_ACK, dlp) < 0) | |
1693 | return -1; | |
1694 | ||
1695 | if (flags != RS_HIPRI) { | |
1696 | vargs_error(0, "dlbindack: DL_OK_ACK was not M_PCPROTO"); | |
1697 | return -1; | |
1698 | } | |
1699 | ||
1700 | if (ctl.len < sizeof (dl_bind_ack_t)) { | |
1701 | vargs_error(0, "dlbindack: short response ctl.len: %d", ctl.len); | |
1702 | return -1; | |
1703 | } | |
1704 | ||
1705 | return 0; | |
1706 | } | |
1707 | ||
1708 | ||
1709 | static int | |
1710 | snoop_strioctl(int fd, int cmd, int timout, int len, char *dp) | |
1711 | { | |
1712 | int rc; | |
1713 | struct strioctl sioc; | |
1714 | ||
1715 | sioc.ic_cmd = cmd; | |
1716 | sioc.ic_timout = timout; | |
1717 | sioc.ic_len = len; | |
1718 | sioc.ic_dp = dp; | |
1719 | ||
1720 | rc = ioctl(fd, I_STR, &sioc); | |
1721 | ||
1722 | if (rc < 0) | |
1723 | return (rc); | |
1724 | else | |
1725 | return (sioc.ic_len); | |
1726 | } | |
1727 | ||
1728 | ||
1729 | #define MAXWAIT 15 | |
1730 | ||
1731 | #ifdef __cplusplus | |
1732 | extern "C" { | |
1733 | #endif | |
1734 | ||
1735 | static void snoop_sigalrm (int); | |
1736 | ||
1737 | #ifdef __cplusplus | |
1738 | } | |
1739 | #endif | |
1740 | ||
1741 | static void | |
1742 | snoop_sigalrm(int i) | |
1743 | { | |
1744 | (void) printf("snoop_sigalrm (%d) : TIMEOUT", i); | |
1745 | ||
1746 | return; | |
1747 | } | |
1748 | ||
1749 | ||
1750 | ||
1751 | static int | |
1752 | snoop_strgetmsg(int fd, | |
1753 | struct strbuf *ctlp, | |
1754 | struct strbuf *datap, | |
1755 | int *flagsp, | |
1756 | const char *caller) | |
1757 | { | |
1758 | int rc; | |
1759 | char errmsg[80]; | |
1760 | ||
1761 | /* | |
1762 | * Start timer. | |
1763 | */ | |
1764 | ||
1765 | (void) signal(SIGALRM, snoop_sigalrm); | |
1766 | ||
1767 | if (alarm(MAXWAIT) < 0) { | |
1768 | (void) snprintf(errmsg, 80, "%s: alarm", caller); | |
1769 | perror(errmsg); | |
1770 | return -1; | |
1771 | } | |
1772 | ||
1773 | /* | |
1774 | * Set flags argument and issue getmsg(). | |
1775 | */ | |
1776 | ||
1777 | *flagsp = 0; | |
1778 | ||
1779 | if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) { | |
1780 | (void) snprintf(errmsg, 80, "%s: getmsg", caller); | |
1781 | perror(errmsg); | |
1782 | return -1; | |
1783 | } | |
1784 | ||
1785 | /* | |
1786 | * Stop timer. | |
1787 | */ | |
1788 | ||
1789 | if (alarm(0) < 0) { | |
1790 | (void) snprintf(errmsg, 80, "%s: alarm", caller); | |
1791 | perror(errmsg); | |
1792 | return -1; | |
1793 | } | |
1794 | ||
1795 | /* | |
1796 | * Check for MOREDATA and/or MORECTL. | |
1797 | */ | |
1798 | ||
1799 | if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) { | |
1800 | vargs_error(0, "%s: MORECTL|MOREDATA", caller); | |
1801 | return -1; | |
1802 | } | |
1803 | ||
1804 | if (rc & MORECTL) { | |
1805 | vargs_error(0, "%s: MORECTL", caller); | |
1806 | return -1; | |
1807 | } | |
1808 | ||
1809 | if (rc & MOREDATA) { | |
1810 | vargs_error(0, "%s: MOREDATA", caller); | |
1811 | return -1; | |
1812 | } | |
1813 | ||
1814 | /* | |
1815 | * Check for at least sizeof(long) control data portion. | |
1816 | */ | |
1817 | ||
1818 | if (ctlp->len < sizeof(long)) { | |
1819 | vargs_error(0, "getmsg: control portion length < sizeof(long): %d", ctlp->len); | |
1820 | return -1; | |
1821 | } | |
1822 | ||
1823 | return 0; | |
1824 | } | |
1825 | ||
1826 | ||
1827 | static const char * | |
1828 | snoop_dlprim(ulong_t prim) | |
1829 | { | |
1830 | #define CASERET(s) case s: return (#s) | |
1831 | ||
1832 | switch ((int)prim) { | |
1833 | ||
1834 | CASERET(DL_INFO_REQ); | |
1835 | CASERET(DL_INFO_ACK); | |
1836 | CASERET(DL_ATTACH_REQ); | |
1837 | CASERET(DL_DETACH_REQ); | |
1838 | CASERET(DL_BIND_REQ); | |
1839 | CASERET(DL_BIND_ACK); | |
1840 | CASERET(DL_UNBIND_REQ); | |
1841 | CASERET(DL_OK_ACK); | |
1842 | CASERET(DL_ERROR_ACK); | |
1843 | CASERET(DL_SUBS_BIND_REQ); | |
1844 | CASERET(DL_SUBS_BIND_ACK); | |
1845 | CASERET(DL_UNITDATA_REQ); | |
1846 | CASERET(DL_UNITDATA_IND); | |
1847 | CASERET(DL_UDERROR_IND); | |
1848 | CASERET(DL_UDQOS_REQ); | |
1849 | CASERET(DL_CONNECT_REQ); | |
1850 | CASERET(DL_CONNECT_IND); | |
1851 | CASERET(DL_CONNECT_RES); | |
1852 | CASERET(DL_CONNECT_CON); | |
1853 | CASERET(DL_TOKEN_REQ); | |
1854 | CASERET(DL_TOKEN_ACK); | |
1855 | CASERET(DL_DISCONNECT_REQ); | |
1856 | CASERET(DL_DISCONNECT_IND); | |
1857 | CASERET(DL_RESET_REQ); | |
1858 | CASERET(DL_RESET_IND); | |
1859 | CASERET(DL_RESET_RES); | |
1860 | CASERET(DL_RESET_CON); | |
1861 | ||
1862 | default: | |
1863 | fprintf(stderr, "snoop_dlprim: unknown primitive 0x%x", prim); | |
1864 | return "unknown primitive"; | |
1865 | } | |
1866 | } | |
1867 | ||
1868 | ||
1869 | static int | |
1870 | snoop_expecting (int prim, union DL_primitives *dlp) | |
1871 | { | |
1872 | if (dlp->dl_primitive != (ulong_t) prim) { | |
1873 | fprintf(stderr, "Failed to initialize device for snooping \n"); | |
1874 | vargs_error(0, "expected %s got %s", snoop_dlprim(prim), | |
1875 | snoop_dlprim(dlp->dl_primitive)); | |
1876 | return -1; | |
1877 | } | |
1878 | ||
1879 | return 0; | |
1880 | } | |
1881 | ||
1882 | ||
1883 | ||
1884 | ||
1885 | ||
1886 | void | |
1887 | vargs_error(int thresh, const char *fmt, ...) | |
1888 | { | |
1889 | if (netsim_debug >= thresh) { | |
1890 | va_list ap; | |
1891 | ||
1892 | va_start(ap, fmt); | |
1893 | vfprintf(stderr, fmt, ap); | |
1894 | (void) fprintf(stderr, "\n"); | |
1895 | va_end(ap); | |
1896 | /* exit(1); NOT ACCEPTABLE !!! */ | |
1897 | } | |
1898 | } | |
1899 | ||
1900 | ||
1901 | ||
1902 | ||
1903 | ||
1904 | ||
1905 | ||
1906 | //////////////////////////////////////////////////////////////////////////////// | |
1907 | // // | |
1908 | // The following section is for Common utility functions // | |
1909 | // // | |
1910 | //////////////////////////////////////////////////////////////////////////////// | |
1911 | ||
1912 | ||
1913 | ||
1914 | /* | |
1915 | * this ether_cksum function was copied from Gigabit Ethernet driver, | |
1916 | * which does not inspire much confidence, look at the mish-mash of | |
1917 | * indexed and pointed memory references... | |
1918 | */ | |
1919 | #if 1 | |
1920 | uint16_t | |
1921 | ether_chksum(char *buf, int offset, int len) | |
1922 | { | |
1923 | int index, count; | |
1924 | uint_t csum; | |
1925 | ushort_t *shortP, value; | |
1926 | ||
1927 | value = 0; | |
1928 | csum = 0; | |
1929 | ||
1930 | count = len & (~0x1); | |
1931 | shortP = (ushort_t *) (buf + offset); | |
1932 | ||
1933 | if (((unsigned long ) shortP) & 0x1) { | |
1934 | fprintf(stderr, "ERROR: ether_cksum odd address. src %p \n", shortP); | |
1935 | return -1; exit(1); | |
1936 | } | |
1937 | ||
1938 | for (index=offset; index<(count+offset); index += sizeof(ushort_t)) | |
1939 | csum += *shortP++; | |
1940 | ||
1941 | if (len & 0x1) { | |
1942 | value = buf[index] << 8; | |
1943 | csum += value; | |
1944 | } | |
1945 | ||
1946 | while (csum>>16) | |
1947 | csum = (csum & 0xffff) + (csum >> 16); | |
1948 | ||
1949 | csum = ~csum; | |
1950 | csum = csum & 0x0000FFFF; | |
1951 | ||
1952 | return csum; | |
1953 | } | |
1954 | #else | |
1955 | // | |
1956 | // a little bit simpler version! | |
1957 | // | |
1958 | uint16_t | |
1959 | ether_chksum(char *buf, int offset, int len) | |
1960 | { | |
1961 | ushort_t *p = (ushort_t*) (buf + offset); | |
1962 | int csum = 0; | |
1963 | ||
1964 | // add up all the whole double-bytes... | |
1965 | for (; len>1; len-=2) | |
1966 | csum += *p++; | |
1967 | ||
1968 | // and if there is an odd byte at the end... | |
1969 | if (len) | |
1970 | csum += (*((unsigned char *)p)) & 0xff00; // big-endian !!! | |
1971 | ||
1972 | // now wrap around the checksum overflow | |
1973 | while (csum>>16) | |
1974 | csum = (csum & 0xffff) + (csum >> 16); | |
1975 | ||
1976 | // finish by taking the 1's complement | |
1977 | csum = (~csum) & 0x0000ffff; | |
1978 | ||
1979 | return csum; | |
1980 | } | |
1981 | #endif | |
1982 | ||
1983 | ||
1984 | ||
1985 | // | |
1986 | // TCP checksum including the "pseudo header" of fields from ip header | |
1987 | // | |
1988 | int tcp_chksum (ethpacket_t * pkt) | |
1989 | { | |
1990 | ushort_t *p = (ushort_t*) pkt; | |
1991 | int hdrcsum = 0; | |
1992 | int csum = 0; | |
1993 | int bytes = ETHHDRSZ + pkt->u.ip.iplen; // Total pkt-len Incl ether hdr. | |
1994 | int i; | |
1995 | ||
1996 | // IP protocol | |
1997 | csum = (p[11] & 0x00ff); | |
1998 | ||
1999 | // IP data length | |
2000 | csum += (pkt->u.ip.iplen - 4*(pkt->u.ip.verlen & 0x0f)); | |
2001 | ||
2002 | // IP src and dest addrs | |
2003 | csum += p[13] + p[14] + p[15] + p[16]; | |
2004 | ||
2005 | // now the TCP header and data | |
2006 | for (i=17; i<(bytes/2); i++) | |
2007 | csum += p[i]; | |
2008 | ||
2009 | // and if there is an odd byte at the end... | |
2010 | if (bytes & 0x1) | |
2011 | csum += p[i] & 0xff00; | |
2012 | ||
2013 | // now wrap the checksum overflow back around | |
2014 | while (csum>>16) | |
2015 | csum = (csum & 0xffff) + (csum >> 16); | |
2016 | ||
2017 | // finish by taking the 1's complement | |
2018 | csum = (~csum) & 0x0000ffff; | |
2019 | ||
2020 | return csum; | |
2021 | } | |
2022 | ||
2023 | ||
2024 | ||
2025 | // compute the raw checksum of just the tcp pseudo header | |
2026 | // | |
2027 | int tcp_pseudocs (ethpacket_t * pkt) | |
2028 | { | |
2029 | ushort_t *p = (ushort_t*) pkt; | |
2030 | int csum = 0; | |
2031 | int bytes = ETHHDRSZ + pkt->u.ip.iplen; // Total pkt-len Incl ether hdr. | |
2032 | int i; | |
2033 | ||
2034 | // IP protocol | |
2035 | csum = (p[11] & 0x00ff); | |
2036 | ||
2037 | // IP data length | |
2038 | csum += (pkt->u.ip.iplen - 4*(pkt->u.ip.verlen & 0x0f)); | |
2039 | ||
2040 | // IP src and dest addrs | |
2041 | csum += p[13] + p[14] + p[15] + p[16]; | |
2042 | ||
2043 | ||
2044 | // now wrap the checksum overflow back around | |
2045 | while (csum>>16) | |
2046 | csum = (csum & 0xffff) + (csum >> 16); | |
2047 | ||
2048 | // raw checksum, no 1's complement of the result here... | |
2049 | ||
2050 | return csum; | |
2051 | } | |
2052 | ||
2053 | ||
2054 | ||
2055 | ||
2056 | ||
2057 | ||
2058 | ||
2059 | ||
2060 | uint16_t | |
2061 | ether_reverse_hword(uint16_t value) | |
2062 | { | |
2063 | char reverse_buf[2]; | |
2064 | ||
2065 | reverse_buf[0] = value & 0x00FF; | |
2066 | reverse_buf[1] = (value >> 8) & 0x00FF; | |
2067 | ||
2068 | return *(uint16_t *) reverse_buf; | |
2069 | } | |
2070 | ||
2071 | ||
2072 | uint32_t | |
2073 | ether_reverse_word(uint32_t value) | |
2074 | { | |
2075 | char reverse_buf[4]; | |
2076 | ||
2077 | reverse_buf[0] = value & 0x00FF; | |
2078 | reverse_buf[1] = (value >> 8) & 0x00FF; | |
2079 | reverse_buf[2] = (value >> 16) & 0x00FF; | |
2080 | reverse_buf[3] = (value >> 24) & 0x00FF; | |
2081 | ||
2082 | return *(uint32_t *) reverse_buf; | |
2083 | } | |
2084 | ||
2085 | ||
2086 | uint64_t | |
2087 | ether_reverse_lword(uint64_t value) | |
2088 | { | |
2089 | char reverse_buf[8]; | |
2090 | ||
2091 | reverse_buf[0] = value & 0x00FF; | |
2092 | reverse_buf[1] = (value >> 8) & 0x00FF; | |
2093 | reverse_buf[2] = (value >> 16) & 0x00FF; | |
2094 | reverse_buf[3] = (value >> 24) & 0x00FF; | |
2095 | reverse_buf[4] = (value >> 32) & 0x00FF; | |
2096 | reverse_buf[5] = (value >> 40) & 0x00FF; | |
2097 | reverse_buf[6] = (value >> 48) & 0x00FF; | |
2098 | reverse_buf[7] = (value >> 56) & 0x00FF; | |
2099 | ||
2100 | return *(uint64_t *) reverse_buf; | |
2101 | } | |
2102 | ||
2103 | ||
2104 | ||
2105 | ||
2106 | // --------------------------------------------------------------------------- | |
2107 | // SNOOP | |
2108 | // debug levels: 0= nada; 1= decoded; 2= raw hex | |
2109 | // | |
2110 | int | |
2111 | netsim_snoop (char * buf, int buflen, int dbglevel) | |
2112 | { | |
2113 | int cs, pktlen; | |
2114 | if (dbglevel >= 1) { // ------------------------------- | |
2115 | ||
2116 | ethpacket_t * packet = (ethpacket_t*) buf; | |
2117 | int et,ipp; | |
2118 | et = eth_type(packet); | |
2119 | fprintf (stderr, "eth/%d{mac:%02x->%02x, ", buflen, | |
2120 | eth_srcMAC(packet) & 0xff, | |
2121 | eth_dstMAC(packet) & 0xff); | |
2122 | switch (et) { | |
2123 | case ET_IPv4: { | |
2124 | pktlen = ETHHDRSZ + packet->u.ip.iplen; | |
2125 | fprintf(stderr,"ip/%d", packet->u.ip.iplen); | |
2126 | ipp = eth_ipproto(packet); | |
2127 | fprintf (stderr, "{ip:%d->%d, ", | |
2128 | eth_srcIP(packet) & 0xff, | |
2129 | eth_dstIP(packet) & 0xff); | |
2130 | switch (ipp) { | |
2131 | case IP_TCP: { | |
2132 | fprintf(stderr,"tcp"); | |
2133 | if (eth_tcpzlenack(packet)) { /* happens a lot */ | |
2134 | fprintf(stderr, "-ack(%s)\n", | |
2135 | eth_tcp_string(eth_srcPORT(packet))); | |
2136 | break; | |
2137 | } | |
2138 | if (packet->u.ip.u.tcp.flags & 0x0002/*TCP_SYN_FLAG*/) | |
2139 | fprintf(stderr, "connect("); | |
2140 | if (packet->u.ip.u.tcp.flags & 0x0001/*TCP_FIN_FLAG*/) | |
2141 | fprintf(stderr, "disconn("); | |
2142 | ||
2143 | fprintf(stderr," %s->%d", | |
2144 | eth_tcp_string(eth_srcPORT(packet)), | |
2145 | eth_tcp_string(eth_dstPORT(packet))); | |
2146 | ||
2147 | if (packet->u.ip.u.tcp.flags & 0x0002/*TCP_SYN_FLAG*/) | |
2148 | fprintf(stderr, ")"); | |
2149 | if (packet->u.ip.u.tcp.flags & 0x0001/*TCP_FIN_FLAG*/) | |
2150 | fprintf(stderr, ")"); | |
2151 | if ((cs = tcp_chksum (packet)) != 0) | |
2152 | fprintf(stderr," ***chksum error 0x%04x*** ", cs); | |
2153 | } break; | |
2154 | ||
2155 | case IP_UDP: { | |
2156 | fprintf(stderr,"udp/%d", packet->u.ip.u.udp.udplen); | |
2157 | fprintf(stderr," %d->%d", packet->u.ip.u.udp.srcPORT, | |
2158 | packet->u.ip.u.udp.dstPORT); | |
2159 | if ((cs = tcp_chksum (packet)) != 0) | |
2160 | fprintf(stderr," ***chksum error 0x%04x*** ", cs); | |
2161 | } break; | |
2162 | ||
2163 | case IP_IP: { | |
2164 | fprintf(stderr," %s", "ip-encaps");/*ip-encapsulation*/ | |
2165 | } break; | |
2166 | ||
2167 | case IP_ICMP: { | |
2168 | fprintf(stderr," %s", eth_icmp_string ( | |
2169 | eth_icmptype (packet), eth_icmpcode (packet))); | |
2170 | } break; | |
2171 | ||
2172 | case IP_IGMP: { | |
2173 | fprintf(stderr," %s", "igmp");/*gateway-management-prot*/ | |
2174 | } break; | |
2175 | ||
2176 | case IP_GGP: { | |
2177 | fprintf(stderr," %s", "ggp");/*gateway-to-gateway-prot*/ | |
2178 | } break; | |
2179 | ||
2180 | case IP_EGP: { | |
2181 | fprintf(stderr," %s", "ext-gateway");/*exterior-gw-prot*/ | |
2182 | } break; | |
2183 | ||
2184 | case IP_IGP: { | |
2185 | fprintf(stderr," %s", "int-gateway");/*interior-gw-prot*/ | |
2186 | } break; | |
2187 | ||
2188 | default: { // unknown ip-header-protocol field | |
2189 | fprintf (stderr, " %d", ipp); | |
2190 | } break; | |
2191 | } | |
2192 | } break; | |
2193 | case ET_ARP: { | |
2194 | pktlen = ETHHDRSZ + sizeof(packet->u.arp); | |
2195 | if (packet->u.arp.op == 1) | |
2196 | fprintf (stderr, "arp rqst %d", packet->u.arp.dstIP[3]); | |
2197 | else if (packet->u.arp.op == 2) | |
2198 | fprintf (stderr, "arp reply %d", packet->u.arp.dstIP[3]); | |
2199 | else | |
2200 | fprintf (stderr, "arp ???"); | |
2201 | } break; | |
2202 | case ET_RARP: { | |
2203 | pktlen = ETHHDRSZ + sizeof(packet->u.arp); | |
2204 | if (packet->u.arp.op == 3) | |
2205 | fprintf (stderr, "rarp rqst %d", packet->u.arp.dstIP[3]); | |
2206 | else if (packet->u.arp.op == 4) | |
2207 | fprintf (stderr, "rarp reply %d",packet->u.arp.dstIP[3]); | |
2208 | else | |
2209 | fprintf (stderr, "rarp ???"); | |
2210 | } break; | |
2211 | default: { // unknown ether-header-type field | |
2212 | pktlen = buflen; | |
2213 | fprintf (stderr, " %d", et); | |
2214 | } break; | |
2215 | } | |
2216 | fprintf (stderr, "}\n"); | |
2217 | ||
2218 | } | |
2219 | if (dbglevel >= 2) { | |
2220 | if (pktlen != buflen) { | |
2221 | fprintf(stderr,"------ length of buf/%d != pkt/%d \n", buflen, pktlen); | |
2222 | } | |
2223 | } | |
2224 | ||
2225 | ||
2226 | if (dbglevel >= 3) { // -------------------------------------- | |
2227 | int i; | |
2228 | ||
2229 | fprintf(stderr, "\n"); | |
2230 | for (i=0; i<pktlen; i+=16) { | |
2231 | int j,lim; | |
2232 | char out[17]; | |
2233 | lim = pktlen-i; | |
2234 | if (lim>16) lim = 16; | |
2235 | fprintf(stderr, "%04x :",i); | |
2236 | for (j=0; j<lim; j++) { | |
2237 | int c = *(unsigned char *)&(buf[i+j]); | |
2238 | fprintf(stderr, " %02x",c); | |
2239 | out[j] = c>=32 && c<127 ? c : '.'; | |
2240 | } | |
2241 | out[j] = 0; | |
2242 | for (; j<16; j++) fprintf(stderr, " .."); | |
2243 | fprintf(stderr, "\t: %s\n",out); | |
2244 | } | |
2245 | fprintf(stderr, "\n"); | |
2246 | } | |
2247 | ||
2248 | if (dbglevel >= 4) { // -------------------------------------- | |
2249 | } | |
2250 | return 1; | |
2251 | } | |
2252 | ||
2253 | ||
2254 | ||
2255 | ||
2256 | ||
2257 | // these aren't appropriate for inlining, but they have to go somewhere... | |
2258 | ||
2259 | const char * eth_tcp_string (int tcptype) | |
2260 | { | |
2261 | static char buf[10]; | |
2262 | ||
2263 | switch (tcptype) { | |
2264 | case TCP_ECHO: return "echo"; | |
2265 | case TCP_FTPDATA: return "ftpdata"; | |
2266 | case TCP_FTP: return "ftp"; | |
2267 | case TCP_SSH: return "ssh"; | |
2268 | case TCP_TELNET: return "telnet"; | |
2269 | case TCP_TIME: return "time"; | |
2270 | case TCP_DNS: return "dns"; | |
2271 | case TCP_HTTP: return "http"; | |
2272 | case TCP_HTTPS: return "https"; | |
2273 | case TCP_SUNRPC: return "sunrpc"; | |
2274 | case TCP_LDAP: return "ldap"; | |
2275 | case TCP_REXEC: return "rexec"; | |
2276 | case TCP_RLOGIN: return "rlogin"; | |
2277 | case TCP_RSHELL: return "rshell"; | |
2278 | default: | |
2279 | sprintf(&buf[0], "%d", tcptype); | |
2280 | return &buf[0]; | |
2281 | } | |
2282 | } | |
2283 | ||
2284 | const char * eth_icmp_string (int icmptype, int icmpcode) | |
2285 | { | |
2286 | static char buf[10]; | |
2287 | ||
2288 | switch (icmptype) { | |
2289 | case ICMP_ECHOREPLY: return "echo_reply"; | |
2290 | case ICMP_UNREACHABLE: | |
2291 | switch (icmpcode) { | |
2292 | case 0: return "network_unreachable"; | |
2293 | case 1: return "host_unreachable"; | |
2294 | case 2: return "protocol_unreachable"; | |
2295 | case 3: return "port_unreachable"; | |
2296 | case 4: return "fragment_unreachable"; | |
2297 | case 5: return "route_unreachable"; | |
2298 | case 6: return "network_unknown"; | |
2299 | case 7: return "host_unknown"; | |
2300 | case 8: return "obsolete_unreachable"; | |
2301 | case 9: return "network_prohibited"; | |
2302 | case 10: return "host_prohibited"; | |
2303 | case 11: return "network_tos_unreachable"; | |
2304 | case 12: return "host_tos_unreachable"; | |
2305 | default: return "unreachable_?"; | |
2306 | } | |
2307 | case ICMP_SRCQUENCH: return "source_quench"; | |
2308 | case ICMP_REDIRECT: | |
2309 | switch (icmpcode) { | |
2310 | case 0: return "redirect_network"; | |
2311 | case 1: return "redirect_host"; | |
2312 | case 2: return "redirect_tos_network"; | |
2313 | case 3: return "redirect_tos_host"; | |
2314 | default: return "redirect_?"; | |
2315 | } | |
2316 | case ICMP_ECHO: return "echo_request"; | |
2317 | case ICMP_ROUTERREPLY: return "router_reply"; | |
2318 | case ICMP_ROUTERREQST: return "router_request"; | |
2319 | case ICMP_TIMEOUT: return "time_exceeded"; | |
2320 | case ICMP_INVARG: return "invalid_parameter"; | |
2321 | case ICMP_TIMESTAMP: return "timestamp_request"; | |
2322 | case ICMP_TSTAMPREPLY: return "timestamp_reply"; | |
2323 | case ICMP_INFO: return "obsolete_request"; | |
2324 | case ICMP_INFOREPLY: return "obsolete_reply"; | |
2325 | case ICMP_MASK: return "mask_request"; | |
2326 | case ICMP_MASKREPLY: return "mask_reply"; | |
2327 | default: | |
2328 | sprintf(&buf[0], "%d", icmptype); | |
2329 | return &buf[0]; | |
2330 | } | |
2331 | } | |
2332 |