Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1988, 1992 The University of Utah and the Center | |
3 | * for Software Science (CSS). | |
4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * the Center for Software Science of the University of Utah Computer | |
9 | * Science Department. CSS requests users of this software to return | |
10 | * to css-dist@cs.utah.edu any improvements that they make and grant | |
11 | * CSS redistribution rights. | |
12 | * | |
13 | * Redistribution and use in source and binary forms, with or without | |
14 | * modification, are permitted provided that the following conditions | |
15 | * are met: | |
16 | * 1. Redistributions of source code must retain the above copyright | |
17 | * notice, this list of conditions and the following disclaimer. | |
18 | * 2. Redistributions in binary form must reproduce the above copyright | |
19 | * notice, this list of conditions and the following disclaimer in the | |
20 | * documentation and/or other materials provided with the distribution. | |
dc71b7ab | 21 | * 3. Neither the name of the University nor the names of its contributors |
984263bc MD |
22 | * may be used to endorse or promote products derived from this software |
23 | * without specific prior written permission. | |
24 | * | |
25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
35 | * SUCH DAMAGE. | |
36 | * | |
37 | * from: @(#)rmpproto.c 8.1 (Berkeley) 6/4/93 | |
38 | * | |
39 | * From: Utah Hdr: rmpproto.c 3.1 92/07/06 | |
40 | * Author: Jeff Forys, University of Utah CSS | |
1de703da MD |
41 | * |
42 | * @(#)rmpproto.c 8.1 (Berkeley) 6/4/93 | |
43 | * $FreeBSD: src/libexec/rbootd/rmpproto.c,v 1.6.2.1 2001/02/18 02:54:11 kris Exp $ | |
984263bc MD |
44 | */ |
45 | ||
984263bc MD |
46 | #include <sys/param.h> |
47 | #include <sys/time.h> | |
48 | ||
49 | #include <errno.h> | |
50 | #include <fcntl.h> | |
51 | #include <stdio.h> | |
52 | #include <string.h> | |
53 | #include <syslog.h> | |
54 | #include <unistd.h> | |
55 | #include "defs.h" | |
56 | ||
57 | /* | |
58 | ** ProcessPacket -- determine packet type and do what's required. | |
59 | ** | |
60 | ** An RMP BOOT packet has been received. Look at the type field | |
61 | ** and process Boot Requests, Read Requests, and Boot Complete | |
62 | ** packets. Any other type will be dropped with a warning msg. | |
63 | ** | |
64 | ** Parameters: | |
65 | ** rconn - the new connection | |
66 | ** client - list of files available to this host | |
67 | ** | |
68 | ** Returns: | |
69 | ** Nothing. | |
70 | ** | |
71 | ** Side Effects: | |
72 | ** - If this is a valid boot request, it will be added to | |
73 | ** the linked list of outstanding requests (RmpConns). | |
74 | ** - If this is a valid boot complete, its associated | |
75 | ** entry in RmpConns will be deleted. | |
76 | ** - Also, unless we run out of memory, a reply will be | |
77 | ** sent to the host that sent the packet. | |
78 | */ | |
79 | void | |
89a89091 | 80 | ProcessPacket(RMPCONN *rconn, CLIENT *client) |
984263bc MD |
81 | { |
82 | struct rmp_packet *rmp; | |
83 | RMPCONN *rconnout; | |
84 | ||
85 | rmp = &rconn->rmp; /* cache pointer to RMP packet */ | |
86 | ||
87 | switch(rmp->r_type) { /* do what we came here to do */ | |
88 | case RMP_BOOT_REQ: /* boot request */ | |
89 | if ((rconnout = NewConn(rconn)) == NULL) | |
90 | return; | |
91 | ||
92 | /* | |
93 | * If the Session ID is 0xffff, this is a "probe" | |
94 | * packet and we do not want to add the connection | |
95 | * to the linked list of active connections. There | |
96 | * are two types of probe packets, if the Sequence | |
97 | * Number is 0 they want to know our host name, o/w | |
98 | * they want the name of the file associated with | |
99 | * the number spec'd by the Sequence Number. | |
100 | * | |
101 | * If this is an actual boot request, open the file | |
102 | * and send a reply. If SendBootRepl() does not | |
103 | * return 0, add the connection to the linked list | |
104 | * of active connections, otherwise delete it since | |
105 | * an error was encountered. | |
106 | */ | |
107 | if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) { | |
108 | if (WORDZE(rmp->r_brq.rmp_seqno)) | |
109 | (void) SendServerID(rconnout); | |
110 | else | |
111 | (void) SendFileNo(rmp, rconnout, | |
112 | client? client->files: | |
113 | BootFiles); | |
114 | FreeConn(rconnout); | |
115 | } else { | |
116 | if (SendBootRepl(rmp, rconnout, | |
117 | client? client->files: BootFiles)) | |
118 | AddConn(rconnout); | |
119 | else | |
120 | FreeConn(rconnout); | |
121 | } | |
122 | break; | |
123 | ||
124 | case RMP_BOOT_REPL: /* boot reply (not valid) */ | |
125 | syslog(LOG_WARNING, "%s: sent a boot reply", | |
126 | EnetStr(rconn)); | |
127 | break; | |
128 | ||
129 | case RMP_READ_REQ: /* read request */ | |
130 | /* | |
131 | * Send a portion of the boot file. | |
132 | */ | |
133 | (void) SendReadRepl(rconn); | |
134 | break; | |
135 | ||
136 | case RMP_READ_REPL: /* read reply (not valid) */ | |
137 | syslog(LOG_WARNING, "%s: sent a read reply", | |
138 | EnetStr(rconn)); | |
139 | break; | |
140 | ||
141 | case RMP_BOOT_DONE: /* boot complete */ | |
142 | /* | |
143 | * Remove the entry from the linked list of active | |
144 | * connections. | |
145 | */ | |
146 | (void) BootDone(rconn); | |
147 | break; | |
148 | ||
149 | default: /* unknown RMP packet type */ | |
150 | syslog(LOG_WARNING, "%s: unknown packet type (%u)", | |
151 | EnetStr(rconn), rmp->r_type); | |
152 | } | |
153 | } | |
154 | ||
155 | /* | |
156 | ** SendServerID -- send our host name to who ever requested it. | |
157 | ** | |
158 | ** Parameters: | |
159 | ** rconn - the reply packet to be formatted. | |
160 | ** | |
161 | ** Returns: | |
162 | ** 1 on success, 0 on failure. | |
163 | ** | |
164 | ** Side Effects: | |
165 | ** none. | |
166 | */ | |
167 | int | |
89a89091 | 168 | SendServerID(RMPCONN *rconn) |
984263bc MD |
169 | { |
170 | struct rmp_packet *rpl; | |
171 | char *src, *dst; | |
172 | u_int8_t *size; | |
173 | ||
174 | rpl = &rconn->rmp; /* cache ptr to RMP packet */ | |
175 | ||
176 | /* | |
177 | * Set up assorted fields in reply packet. | |
178 | */ | |
179 | rpl->r_brpl.rmp_type = RMP_BOOT_REPL; | |
180 | rpl->r_brpl.rmp_retcode = RMP_E_OKAY; | |
181 | ZEROWORD(rpl->r_brpl.rmp_seqno); | |
182 | rpl->r_brpl.rmp_session = 0; | |
183 | rpl->r_brpl.rmp_version = htons(RMP_VERSION); | |
184 | ||
185 | size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */ | |
186 | ||
187 | /* | |
188 | * Copy our host name into the reply packet incrementing the | |
189 | * length as we go. Stop at RMP_HOSTLEN or the first dot. | |
190 | */ | |
191 | src = MyHost; | |
192 | dst = (char *) &rpl->r_brpl.rmp_flnm; | |
193 | for (*size = 0; *size < RMP_HOSTLEN; (*size)++) { | |
194 | if (*src == '.' || *src == '\0') | |
195 | break; | |
196 | *dst++ = *src++; | |
197 | } | |
198 | ||
199 | rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ | |
200 | ||
201 | return(SendPacket(rconn)); /* send packet */ | |
202 | } | |
203 | ||
204 | /* | |
205 | ** SendFileNo -- send the name of a bootable file to the requester. | |
206 | ** | |
207 | ** Parameters: | |
208 | ** req - RMP BOOT packet containing the request. | |
209 | ** rconn - the reply packet to be formatted. | |
210 | ** filelist - list of files available to the requester. | |
211 | ** | |
212 | ** Returns: | |
213 | ** 1 on success, 0 on failure. | |
214 | ** | |
215 | ** Side Effects: | |
216 | ** none. | |
217 | */ | |
218 | int | |
89a89091 | 219 | SendFileNo(struct rmp_packet *req, RMPCONN *rconn, char *filelist[]) |
984263bc MD |
220 | { |
221 | struct rmp_packet *rpl; | |
222 | char *src, *dst; | |
223 | u_int8_t *size; | |
224 | int i; | |
225 | ||
226 | GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */ | |
227 | rpl = &rconn->rmp; /* cache ptr to RMP packet */ | |
228 | ||
229 | /* | |
230 | * Set up assorted fields in reply packet. | |
231 | */ | |
232 | rpl->r_brpl.rmp_type = RMP_BOOT_REPL; | |
233 | PUTWORD(i, rpl->r_brpl.rmp_seqno); | |
234 | i--; | |
235 | rpl->r_brpl.rmp_session = 0; | |
236 | rpl->r_brpl.rmp_version = htons(RMP_VERSION); | |
237 | ||
238 | size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */ | |
239 | *size = 0; /* init length to zero */ | |
240 | ||
241 | /* | |
242 | * Copy the file name into the reply packet incrementing the | |
243 | * length as we go. Stop at end of string or when RMPBOOTDATA | |
244 | * characters have been copied. Also, set return code to | |
245 | * indicate success or "no more files". | |
246 | */ | |
247 | if (i < C_MAXFILE && filelist[i] != NULL) { | |
248 | src = filelist[i]; | |
249 | dst = (char *)&rpl->r_brpl.rmp_flnm; | |
250 | for (; *src && *size < RMPBOOTDATA; (*size)++) { | |
251 | if (*src == '\0') | |
252 | break; | |
253 | *dst++ = *src++; | |
254 | } | |
255 | rpl->r_brpl.rmp_retcode = RMP_E_OKAY; | |
256 | } else | |
257 | rpl->r_brpl.rmp_retcode = RMP_E_NODFLT; | |
258 | ||
259 | rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ | |
260 | ||
261 | return(SendPacket(rconn)); /* send packet */ | |
262 | } | |
263 | ||
264 | /* | |
265 | ** SendBootRepl -- open boot file and respond to boot request. | |
266 | ** | |
267 | ** Parameters: | |
268 | ** req - RMP BOOT packet containing the request. | |
269 | ** rconn - the reply packet to be formatted. | |
270 | ** filelist - list of files available to the requester. | |
271 | ** | |
272 | ** Returns: | |
273 | ** 1 on success, 0 on failure. | |
274 | ** | |
275 | ** Side Effects: | |
276 | ** none. | |
277 | */ | |
278 | int | |
89a89091 | 279 | SendBootRepl(struct rmp_packet *req, RMPCONN *rconn, char *filelist[]) |
984263bc MD |
280 | { |
281 | int retval; | |
282 | char *filename, filepath[RMPBOOTDATA+1]; | |
283 | RMPCONN *oldconn; | |
284 | struct rmp_packet *rpl; | |
285 | char *src, *dst1, *dst2; | |
286 | u_int8_t i; | |
287 | ||
288 | /* | |
289 | * If another connection already exists, delete it since we | |
290 | * are obviously starting again. | |
291 | */ | |
292 | if ((oldconn = FindConn(rconn)) != NULL) { | |
293 | syslog(LOG_WARNING, "%s: dropping existing connection", | |
294 | EnetStr(oldconn)); | |
295 | RemoveConn(oldconn); | |
296 | } | |
297 | ||
298 | rpl = &rconn->rmp; /* cache ptr to RMP packet */ | |
299 | ||
300 | /* | |
301 | * Set up assorted fields in reply packet. | |
302 | */ | |
303 | rpl->r_brpl.rmp_type = RMP_BOOT_REPL; | |
304 | COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno); | |
305 | rpl->r_brpl.rmp_session = htons(GenSessID()); | |
306 | rpl->r_brpl.rmp_version = htons(RMP_VERSION); | |
307 | rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize; | |
308 | ||
309 | /* | |
310 | * Copy file name to `filepath' string, and into reply packet. | |
311 | */ | |
312 | src = &req->r_brq.rmp_flnm; | |
313 | dst1 = filepath; | |
314 | dst2 = &rpl->r_brpl.rmp_flnm; | |
315 | for (i = 0; i < req->r_brq.rmp_flnmsize; i++) | |
316 | *dst1++ = *dst2++ = *src++; | |
317 | *dst1 = '\0'; | |
318 | ||
319 | /* | |
320 | * If we are booting HP-UX machines, their secondary loader will | |
321 | * ask for files like "/hp-ux". As a security measure, we do not | |
322 | * allow boot files to lay outside the boot directory (unless they | |
323 | * are purposely link'd out. So, make `filename' become the path- | |
324 | * stripped file name and spoof the client into thinking that it | |
325 | * really got what it wanted. | |
326 | */ | |
8f5c3d2a SW |
327 | if ((filename = strrchr(filepath, '/')) != NULL) |
328 | filename++; | |
329 | else | |
330 | filename = filepath; | |
984263bc MD |
331 | |
332 | /* | |
333 | * Check that this is a valid boot file name. | |
334 | */ | |
335 | for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++) | |
336 | if (STREQN(filename, filelist[i])) | |
337 | goto match; | |
338 | ||
339 | /* | |
340 | * Invalid boot file name, set error and send reply packet. | |
341 | */ | |
342 | rpl->r_brpl.rmp_retcode = RMP_E_NOFILE; | |
343 | retval = 0; | |
344 | goto sendpkt; | |
345 | ||
346 | match: | |
347 | /* | |
348 | * This is a valid boot file. Open the file and save the file | |
349 | * descriptor associated with this connection and set success | |
350 | * indication. If the file couldnt be opened, set error: | |
351 | * "no such file or dir" - RMP_E_NOFILE | |
352 | * "file table overflow" - RMP_E_BUSY | |
353 | * "too many open files" - RMP_E_BUSY | |
354 | * anything else - RMP_E_OPENFILE | |
355 | */ | |
356 | if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) { | |
357 | rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE: | |
358 | (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY: | |
359 | RMP_E_OPENFILE; | |
360 | retval = 0; | |
361 | } else { | |
362 | rpl->r_brpl.rmp_retcode = RMP_E_OKAY; | |
363 | retval = 1; | |
364 | } | |
365 | ||
366 | sendpkt: | |
367 | syslog(LOG_INFO, "%s: request to boot %s (%s)", | |
368 | EnetStr(rconn), filename, retval? "granted": "denied"); | |
369 | ||
370 | rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize); | |
371 | ||
372 | return (retval & SendPacket(rconn)); | |
373 | } | |
374 | ||
375 | /* | |
376 | ** SendReadRepl -- send a portion of the boot file to the requester. | |
377 | ** | |
378 | ** Parameters: | |
379 | ** rconn - the reply packet to be formatted. | |
380 | ** | |
381 | ** Returns: | |
382 | ** 1 on success, 0 on failure. | |
383 | ** | |
384 | ** Side Effects: | |
385 | ** none. | |
386 | */ | |
387 | int | |
89a89091 | 388 | SendReadRepl(RMPCONN *rconn) |
984263bc MD |
389 | { |
390 | int retval = 0; | |
391 | RMPCONN *oldconn; | |
392 | struct rmp_packet *rpl, *req; | |
393 | int size = 0; | |
394 | int madeconn = 0; | |
395 | ||
396 | /* | |
397 | * Find the old connection. If one doesnt exist, create one only | |
398 | * to return the error code. | |
399 | */ | |
400 | if ((oldconn = FindConn(rconn)) == NULL) { | |
401 | if ((oldconn = NewConn(rconn)) == NULL) | |
402 | return(0); | |
403 | syslog(LOG_ERR, "SendReadRepl: no active connection (%s)", | |
404 | EnetStr(rconn)); | |
405 | madeconn++; | |
406 | } | |
407 | ||
408 | req = &rconn->rmp; /* cache ptr to request packet */ | |
409 | rpl = &oldconn->rmp; /* cache ptr to reply packet */ | |
410 | ||
411 | if (madeconn) { /* no active connection above; abort */ | |
412 | rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; | |
413 | retval = 1; | |
414 | goto sendpkt; | |
415 | } | |
416 | ||
417 | /* | |
418 | * Make sure Session ID's match. | |
419 | */ | |
420 | if (ntohs(req->r_rrq.rmp_session) != | |
421 | ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): | |
422 | ntohs(rpl->r_rrpl.rmp_session))) { | |
423 | syslog(LOG_ERR, "SendReadRepl: bad session id (%s)", | |
424 | EnetStr(rconn)); | |
425 | rpl->r_rrpl.rmp_retcode = RMP_E_BADSID; | |
426 | retval = 1; | |
427 | goto sendpkt; | |
428 | } | |
429 | ||
430 | /* | |
431 | * If the requester asks for more data than we can fit, | |
432 | * silently clamp the request size down to RMPREADDATA. | |
433 | * | |
434 | * N.B. I do not know if this is "legal", however it seems | |
435 | * to work. This is necessary for bpfwrite() on machines | |
436 | * with MCLBYTES less than 1514. | |
437 | */ | |
438 | if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA) | |
439 | req->r_rrq.rmp_size = htons(RMPREADDATA); | |
440 | ||
441 | /* | |
442 | * Position read head on file according to info in request packet. | |
443 | */ | |
444 | GETWORD(req->r_rrq.rmp_offset, size); | |
445 | if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) { | |
446 | syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)", | |
447 | EnetStr(rconn)); | |
448 | rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; | |
449 | retval = 1; | |
450 | goto sendpkt; | |
451 | } | |
452 | ||
453 | /* | |
454 | * Read data directly into reply packet. | |
455 | */ | |
456 | if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data, | |
457 | (int) ntohs(req->r_rrq.rmp_size))) <= 0) { | |
458 | if (size < 0) { | |
459 | syslog(LOG_ERR, "SendReadRepl: read: %m (%s)", | |
460 | EnetStr(rconn)); | |
461 | rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; | |
462 | } else { | |
463 | rpl->r_rrpl.rmp_retcode = RMP_E_EOF; | |
464 | } | |
465 | retval = 1; | |
466 | goto sendpkt; | |
467 | } | |
468 | ||
469 | /* | |
470 | * Set success indication. | |
471 | */ | |
472 | rpl->r_rrpl.rmp_retcode = RMP_E_OKAY; | |
473 | ||
474 | sendpkt: | |
475 | /* | |
476 | * Set up assorted fields in reply packet. | |
477 | */ | |
478 | rpl->r_rrpl.rmp_type = RMP_READ_REPL; | |
479 | COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset); | |
480 | rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session; | |
481 | ||
482 | oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */ | |
483 | ||
484 | retval &= SendPacket(oldconn); /* send packet */ | |
485 | ||
486 | if (madeconn) /* clean up after ourself */ | |
487 | FreeConn(oldconn); | |
488 | ||
489 | return (retval); | |
490 | } | |
491 | ||
492 | /* | |
493 | ** BootDone -- free up memory allocated for a connection. | |
494 | ** | |
495 | ** Parameters: | |
496 | ** rconn - incoming boot complete packet. | |
497 | ** | |
498 | ** Returns: | |
499 | ** 1 on success, 0 on failure. | |
500 | ** | |
501 | ** Side Effects: | |
502 | ** none. | |
503 | */ | |
504 | int | |
89a89091 | 505 | BootDone(RMPCONN *rconn) |
984263bc MD |
506 | { |
507 | RMPCONN *oldconn; | |
508 | struct rmp_packet *rpl; | |
509 | ||
510 | /* | |
511 | * If we cant find the connection, ignore the request. | |
512 | */ | |
513 | if ((oldconn = FindConn(rconn)) == NULL) { | |
514 | syslog(LOG_ERR, "BootDone: no existing connection (%s)", | |
515 | EnetStr(rconn)); | |
516 | return(0); | |
517 | } | |
518 | ||
519 | rpl = &oldconn->rmp; /* cache ptr to RMP packet */ | |
520 | ||
521 | /* | |
522 | * Make sure Session ID's match. | |
523 | */ | |
524 | if (ntohs(rconn->rmp.r_rrq.rmp_session) != | |
525 | ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): | |
526 | ntohs(rpl->r_rrpl.rmp_session))) { | |
527 | syslog(LOG_ERR, "BootDone: bad session id (%s)", | |
528 | EnetStr(rconn)); | |
529 | return(0); | |
530 | } | |
531 | ||
532 | RemoveConn(oldconn); /* remove connection */ | |
533 | ||
534 | syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn)); | |
535 | ||
536 | return(1); | |
537 | } | |
538 | ||
539 | /* | |
540 | ** SendPacket -- send an RMP packet to a remote host. | |
541 | ** | |
542 | ** Parameters: | |
543 | ** rconn - packet to be sent. | |
544 | ** | |
545 | ** Returns: | |
546 | ** 1 on success, 0 on failure. | |
547 | ** | |
548 | ** Side Effects: | |
549 | ** none. | |
550 | */ | |
551 | int | |
89a89091 | 552 | SendPacket(RMPCONN *rconn) |
984263bc MD |
553 | { |
554 | /* | |
555 | * Set Ethernet Destination address to Source (BPF and the enet | |
556 | * driver will take care of getting our source address set). | |
557 | */ | |
558 | memmove((char *)&rconn->rmp.hp_hdr.daddr[0], | |
559 | (char *)&rconn->rmp.hp_hdr.saddr[0], RMP_ADDRLEN); | |
560 | rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr)); | |
561 | ||
562 | /* | |
563 | * Reverse 802.2/HP Extended Source & Destination Access Pts. | |
564 | */ | |
565 | rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP); | |
566 | rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP); | |
567 | ||
568 | /* | |
569 | * Last time this connection was active. | |
570 | */ | |
60233e58 | 571 | (void) gettimeofday(&rconn->tstamp, NULL); |
984263bc MD |
572 | |
573 | if (DbgFp != NULL) /* display packet */ | |
574 | DispPkt(rconn,DIR_SENT); | |
575 | ||
576 | /* | |
577 | * Send RMP packet to remote host. | |
578 | */ | |
579 | return(BpfWrite(rconn)); | |
580 | } |