Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/rbootd/utils.c
34821 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1988, 1992 The University of Utah and the Center
5
* for Software Science (CSS).
6
* Copyright (c) 1992, 1993
7
* The Regents of the University of California. All rights reserved.
8
*
9
* This code is derived from software contributed to Berkeley by
10
* the Center for Software Science of the University of Utah Computer
11
* Science Department. CSS requests users of this software to return
12
* to [email protected] any improvements that they make and grant
13
* CSS redistribution rights.
14
*
15
* Redistribution and use in source and binary forms, with or without
16
* modification, are permitted provided that the following conditions
17
* are met:
18
* 1. Redistributions of source code must retain the above copyright
19
* notice, this list of conditions and the following disclaimer.
20
* 2. Redistributions in binary form must reproduce the above copyright
21
* notice, this list of conditions and the following disclaimer in the
22
* documentation and/or other materials provided with the distribution.
23
* 3. Neither the name of the University nor the names of its contributors
24
* may be used to endorse or promote products derived from this software
25
* without specific prior written permission.
26
*
27
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37
* SUCH DAMAGE.
38
*
39
* From: Utah Hdr: utils.c 3.1 92/07/06
40
* Author: Jeff Forys, University of Utah CSS
41
*/
42
43
#include <sys/param.h>
44
#include <sys/time.h>
45
#include <netinet/in.h>
46
47
#include <fcntl.h>
48
#include <signal.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <syslog.h>
53
#include <time.h>
54
#include <unistd.h>
55
#include "defs.h"
56
57
/*
58
** DispPkt -- Display the contents of an RMPCONN packet.
59
**
60
** Parameters:
61
** rconn - packet to be displayed.
62
** direct - direction packet is going (DIR_*).
63
**
64
** Returns:
65
** Nothing.
66
**
67
** Side Effects:
68
** None.
69
*/
70
void
71
DispPkt(RMPCONN *rconn, int direct)
72
{
73
static const char BootFmt[] = "\t\tRetCode:%u SeqNo:%x SessID:%x Vers:%u";
74
static const char ReadFmt[] = "\t\tRetCode:%u Offset:%x SessID:%x\n";
75
76
struct tm *tmp;
77
struct rmp_packet *rmp;
78
int i, omask;
79
u_int32_t t;
80
81
/*
82
* Since we will be working with RmpConns as well as DbgFp, we
83
* must block signals that can affect either.
84
*/
85
omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
86
87
if (DbgFp == NULL) { /* sanity */
88
(void) sigsetmask(omask);
89
return;
90
}
91
92
/* display direction packet is going using '>>>' or '<<<' */
93
fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
94
95
/* display packet timestamp */
96
tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
97
fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min,
98
tmp->tm_sec, rconn->tstamp.tv_usec);
99
100
/* display src or dst addr and information about network interface */
101
fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName);
102
103
rmp = &rconn->rmp;
104
105
/* display IEEE 802.2 Logical Link Control header */
106
(void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
107
rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl));
108
109
/* display HP extensions to 802.2 Logical Link Control header */
110
(void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",
111
ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap));
112
113
/*
114
* Display information about RMP packet using type field to
115
* determine what kind of packet this is.
116
*/
117
switch(rmp->r_type) {
118
case RMP_BOOT_REQ: /* boot request */
119
(void) fprintf(DbgFp, "\tBoot Request:");
120
GETWORD(rmp->r_brq.rmp_seqno, t);
121
if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
122
if (WORDZE(rmp->r_brq.rmp_seqno))
123
fputs(" (Send Server ID)", DbgFp);
124
else
125
fprintf(DbgFp," (Send Filename #%u)",t);
126
}
127
(void) fputc('\n', DbgFp);
128
(void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
129
t, ntohs(rmp->r_brq.rmp_session),
130
ntohs(rmp->r_brq.rmp_version));
131
(void) fprintf(DbgFp, "\n\t\tMachine Type: ");
132
for (i = 0; i < RMP_MACHLEN; i++)
133
(void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
134
DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
135
break;
136
case RMP_BOOT_REPL: /* boot reply */
137
fprintf(DbgFp, "\tBoot Reply:\n");
138
GETWORD(rmp->r_brpl.rmp_seqno, t);
139
(void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
140
t, ntohs(rmp->r_brpl.rmp_session),
141
ntohs(rmp->r_brpl.rmp_version));
142
DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
143
break;
144
case RMP_READ_REQ: /* read request */
145
(void) fprintf(DbgFp, "\tRead Request:\n");
146
GETWORD(rmp->r_rrq.rmp_offset, t);
147
(void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
148
t, ntohs(rmp->r_rrq.rmp_session));
149
(void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
150
ntohs(rmp->r_rrq.rmp_size));
151
break;
152
case RMP_READ_REPL: /* read reply */
153
(void) fprintf(DbgFp, "\tRead Reply:\n");
154
GETWORD(rmp->r_rrpl.rmp_offset, t);
155
(void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
156
t, ntohs(rmp->r_rrpl.rmp_session));
157
(void) fprintf(DbgFp, "\t\tNoOfBytesSent: %zu\n",
158
rconn->rmplen - RMPREADSIZE(0));
159
break;
160
case RMP_BOOT_DONE: /* boot complete */
161
(void) fprintf(DbgFp, "\tBoot Complete:\n");
162
(void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
163
rmp->r_done.rmp_retcode,
164
ntohs(rmp->r_done.rmp_session));
165
break;
166
default: /* ??? */
167
(void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
168
rmp->r_type);
169
}
170
(void) fputc('\n', DbgFp);
171
(void) fflush(DbgFp);
172
173
(void) sigsetmask(omask); /* reset old signal mask */
174
}
175
176
177
/*
178
** GetEtherAddr -- convert an RMP (Ethernet) address into a string.
179
**
180
** An RMP BOOT packet has been received. Look at the type field
181
** and process Boot Requests, Read Requests, and Boot Complete
182
** packets. Any other type will be dropped with a warning msg.
183
**
184
** Parameters:
185
** addr - array of RMP_ADDRLEN bytes.
186
**
187
** Returns:
188
** Pointer to static string representation of `addr'.
189
**
190
** Side Effects:
191
** None.
192
**
193
** Warnings:
194
** - The return value points to a static buffer; it must
195
** be copied if it's to be saved.
196
*/
197
char *
198
GetEtherAddr(u_int8_t *addr)
199
{
200
static char Hex[] = "0123456789abcdef";
201
static char etherstr[RMP_ADDRLEN*3];
202
int i;
203
char *cp;
204
205
/*
206
* For each byte in `addr', convert it to "<hexchar><hexchar>:".
207
* The last byte does not get a trailing `:' appended.
208
*/
209
i = 0;
210
cp = etherstr;
211
for(;;) {
212
*cp++ = Hex[*addr >> 4 & 0xf];
213
*cp++ = Hex[*addr++ & 0xf];
214
if (++i == RMP_ADDRLEN)
215
break;
216
*cp++ = ':';
217
}
218
*cp = '\0';
219
220
return(etherstr);
221
}
222
223
224
/*
225
** DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
226
**
227
** Parameters:
228
** size - number of bytes to print.
229
** flnm - address of first byte.
230
**
231
** Returns:
232
** Nothing.
233
**
234
** Side Effects:
235
** - Characters are sent to `DbgFp'.
236
*/
237
void
238
DspFlnm(u_int size, char *flnm)
239
{
240
int i;
241
242
(void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size);
243
for (i = 0; i < size; i++)
244
(void) fputc(*flnm++, DbgFp);
245
(void) fputs(">\n", DbgFp);
246
}
247
248
249
/*
250
** NewClient -- allocate memory for a new CLIENT.
251
**
252
** Parameters:
253
** addr - RMP (Ethernet) address of new client.
254
**
255
** Returns:
256
** Ptr to new CLIENT or NULL if we ran out of memory.
257
**
258
** Side Effects:
259
** - Memory will be malloc'd for the new CLIENT.
260
** - If malloc() fails, a log message will be generated.
261
*/
262
CLIENT *
263
NewClient(u_int8_t *addr)
264
{
265
CLIENT *ctmp;
266
267
if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
268
syslog(LOG_ERR, "NewClient: out of memory (%s)",
269
GetEtherAddr(addr));
270
return(NULL);
271
}
272
273
memset(ctmp, 0, sizeof(CLIENT));
274
memmove(&ctmp->addr[0], addr, RMP_ADDRLEN);
275
return(ctmp);
276
}
277
278
/*
279
** FreeClient -- free linked list of Clients.
280
**
281
** Parameters:
282
** None.
283
**
284
** Returns:
285
** Nothing.
286
**
287
** Side Effects:
288
** - All malloc'd memory associated with the linked list of
289
** CLIENTS will be free'd; `Clients' will be set to NULL.
290
**
291
** Warnings:
292
** - This routine must be called with SIGHUP blocked.
293
*/
294
void
295
FreeClients(void)
296
{
297
CLIENT *ctmp;
298
299
while (Clients != NULL) {
300
ctmp = Clients;
301
Clients = Clients->next;
302
FreeClient(ctmp);
303
}
304
}
305
306
/*
307
** NewStr -- allocate memory for a character array.
308
**
309
** Parameters:
310
** str - null terminated character array.
311
**
312
** Returns:
313
** Ptr to new character array or NULL if we ran out of memory.
314
**
315
** Side Effects:
316
** - Memory will be malloc'd for the new character array.
317
** - If malloc() fails, a log message will be generated.
318
*/
319
char *
320
NewStr(char *str)
321
{
322
char *stmp;
323
324
if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {
325
syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
326
return(NULL);
327
}
328
329
(void) strcpy(stmp, str);
330
return(stmp);
331
}
332
333
/*
334
** To save time, NewConn and FreeConn maintain a cache of one RMPCONN
335
** in `LastFree' (defined below).
336
*/
337
338
static RMPCONN *LastFree = NULL;
339
340
/*
341
** NewConn -- allocate memory for a new RMPCONN connection.
342
**
343
** Parameters:
344
** rconn - initialization template for new connection.
345
**
346
** Returns:
347
** Ptr to new RMPCONN or NULL if we ran out of memory.
348
**
349
** Side Effects:
350
** - Memory may be malloc'd for the new RMPCONN (if not cached).
351
** - If malloc() fails, a log message will be generated.
352
*/
353
RMPCONN *
354
NewConn(RMPCONN *rconn)
355
{
356
RMPCONN *rtmp;
357
358
if (LastFree == NULL) { /* nothing cached; make a new one */
359
if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
360
syslog(LOG_ERR, "NewConn: out of memory (%s)",
361
EnetStr(rconn));
362
return(NULL);
363
}
364
} else { /* use the cached RMPCONN */
365
rtmp = LastFree;
366
LastFree = NULL;
367
}
368
369
/*
370
* Copy template into `rtmp', init file descriptor to `-1' and
371
* set ptr to next elem NULL.
372
*/
373
memmove((char *)rtmp, (char *)rconn, sizeof(RMPCONN));
374
rtmp->bootfd = -1;
375
rtmp->next = NULL;
376
377
return(rtmp);
378
}
379
380
/*
381
** FreeConn -- Free memory associated with an RMPCONN connection.
382
**
383
** Parameters:
384
** rtmp - ptr to RMPCONN to be free'd.
385
**
386
** Returns:
387
** Nothing.
388
**
389
** Side Effects:
390
** - Memory associated with `rtmp' may be free'd (or cached).
391
** - File desc associated with `rtmp->bootfd' will be closed.
392
*/
393
void
394
FreeConn(RMPCONN *rtmp)
395
{
396
/*
397
* If the file descriptor is in use, close the file.
398
*/
399
if (rtmp->bootfd >= 0) {
400
(void) close(rtmp->bootfd);
401
rtmp->bootfd = -1;
402
}
403
404
if (LastFree == NULL) /* cache for next time */
405
rtmp = LastFree;
406
else /* already one cached; free this one */
407
free((char *)rtmp);
408
}
409
410
/*
411
** FreeConns -- free linked list of RMPCONN connections.
412
**
413
** Parameters:
414
** None.
415
**
416
** Returns:
417
** Nothing.
418
**
419
** Side Effects:
420
** - All malloc'd memory associated with the linked list of
421
** connections will be free'd; `RmpConns' will be set to NULL.
422
** - If LastFree is != NULL, it too will be free'd & NULL'd.
423
**
424
** Warnings:
425
** - This routine must be called with SIGHUP blocked.
426
*/
427
void
428
FreeConns(void)
429
{
430
RMPCONN *rtmp;
431
432
while (RmpConns != NULL) {
433
rtmp = RmpConns;
434
RmpConns = RmpConns->next;
435
FreeConn(rtmp);
436
}
437
438
if (LastFree != NULL) {
439
free((char *)LastFree);
440
LastFree = NULL;
441
}
442
}
443
444
/*
445
** AddConn -- Add a connection to the linked list of connections.
446
**
447
** Parameters:
448
** rconn - connection to be added.
449
**
450
** Returns:
451
** Nothing.
452
**
453
** Side Effects:
454
** - RmpConn will point to new connection.
455
**
456
** Warnings:
457
** - This routine must be called with SIGHUP blocked.
458
*/
459
void
460
AddConn(RMPCONN *rconn)
461
{
462
if (RmpConns != NULL)
463
rconn->next = RmpConns;
464
RmpConns = rconn;
465
}
466
467
/*
468
** FindConn -- Find a connection in the linked list of connections.
469
**
470
** We use the RMP (Ethernet) address as the basis for determining
471
** if this is the same connection. According to the Remote Maint
472
** Protocol, we can only have one connection with any machine.
473
**
474
** Parameters:
475
** rconn - connection to be found.
476
**
477
** Returns:
478
** Matching connection from linked list or NULL if not found.
479
**
480
** Side Effects:
481
** None.
482
**
483
** Warnings:
484
** - This routine must be called with SIGHUP blocked.
485
*/
486
RMPCONN *
487
FindConn(RMPCONN *rconn)
488
{
489
RMPCONN *rtmp;
490
491
for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
492
if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
493
(char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
494
break;
495
496
return(rtmp);
497
}
498
499
/*
500
** RemoveConn -- Remove a connection from the linked list of connections.
501
**
502
** Parameters:
503
** rconn - connection to be removed.
504
**
505
** Returns:
506
** Nothing.
507
**
508
** Side Effects:
509
** - If found, an RMPCONN will cease to exist and it will
510
** be removed from the linked list.
511
**
512
** Warnings:
513
** - This routine must be called with SIGHUP blocked.
514
*/
515
void
516
RemoveConn(RMPCONN *rconn)
517
{
518
RMPCONN *thisrconn, *lastrconn;
519
520
if (RmpConns == rconn) { /* easy case */
521
RmpConns = RmpConns->next;
522
FreeConn(rconn);
523
} else { /* must traverse linked list */
524
lastrconn = RmpConns; /* set back ptr */
525
thisrconn = lastrconn->next; /* set current ptr */
526
while (thisrconn != NULL) {
527
if (rconn == thisrconn) { /* found it */
528
lastrconn->next = thisrconn->next;
529
FreeConn(thisrconn);
530
break;
531
}
532
lastrconn = thisrconn;
533
thisrconn = thisrconn->next;
534
}
535
}
536
}
537
538