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