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