1 /*
2 * pet.c
3 *
4 * MontaVista IPMI code handling for setting up and receiving platform
5 * event traps.
6 *
7 * Author: MontaVista Software, Inc.
8 * Corey Minyard <minyard@mvista.com>
9 * source@mvista.com
10 *
11 * Copyright 2004 MontaVista Software Inc.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public License
15 * as published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 *
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this program; if not, write to the Free
32 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 */
34
35 /* NOTE: This code requires scan_sysaddr to be set for the BMC
36 connections. */
37
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <stdio.h>
45
46 #include <OpenIPMI/os_handler.h>
47 #include <OpenIPMI/ipmi_err.h>
48 #include <OpenIPMI/ipmi_pet.h>
49 #include <OpenIPMI/ipmi_pef.h>
50 #include <OpenIPMI/ipmi_lanparm.h>
51 #include <OpenIPMI/ipmi_msgbits.h>
52
53 #include <OpenIPMI/internal/ipmi_int.h>
54 #include <OpenIPMI/internal/locked_list.h>
55 #include <OpenIPMI/internal/ipmi_domain.h>
56 #include <OpenIPMI/internal/ipmi_mc.h>
57
58 /* Recheck the PET config every 10 minutes. */
59 #define PET_TIMEOUT_SEC 600
60
61 /* Time between alert retries (in seconds). */
62 #define IPMI_LANPARM_DEFAULT_ALERT_RETRY_TIMEOUT 1
63
64 /* Alerts get retried this many times. */
65 #define IPMI_LANPARM_DEFAULT_ALERT_RETRIES 3
66
67 #define IPMI_PET_ATTR_NAME "ipmi_pet"
68
69
70 /* This data structure defines a data/mask setting for a parameter,
71 either from the LAN or PEF parms. */
72 typedef struct parm_check_s
73 {
74 unsigned char conf_num; /* The number we are interested in. */
75 unsigned char set; /* The specific selector. */
76 unsigned int data_len; /* The length of the data we are using. */
77 unsigned char data[22]; /* The actual data. */
78 unsigned char mask[22]; /* The mask bits used to mask what we compare. */
79 } parm_check_t;
80
81 /* Information for running the timer. Note that there is no lock in
82 the timer, since the timer is only deleted when the pet_lock is
83 held write, we read-lock the pet timer to avoid locking problem. */
84 typedef struct pet_timer_s {
85 int cancelled;
86 int running;
87 os_handler_t *os_hnd;
88 ipmi_lock_t *lock; /* Lock is here because we need it in the timer. */
89 ipmi_pet_t *pet;
90 int err;
91 } pet_timer_t;
92
93 #define NUM_PEF_SETTINGS 4
94 #define NUM_LANPARM_SETTINGS 2
95
96 struct ipmi_pet_s
97 {
98 int destroyed;
99 int in_list;
100
101 unsigned int refcount;
102
103 char name[IPMI_PET_NAME_LEN];
104
105 /* Configuration parameters */
106 ipmi_mcid_t mc;
107 ipmi_domain_id_t domain;
108 struct in_addr ip_addr;
109 char mac_addr[6];
110 unsigned int policy_num;
111 unsigned int eft_sel;
112 unsigned int apt_sel;
113 unsigned int lan_dest_sel;
114
115 unsigned int channel;
116 ipmi_pet_t *pet;
117 int pef_err;
118 int pef_lock_broken;
119 int lanparm_err;
120 int lanparm_lock_broken;
121 int changed_lanparm;
122 int changed_pef;
123
124 int lanparm_check_pos;
125 ipmi_lanparm_t *lanparm;
126
127 int pef_check_pos;
128 ipmi_pef_t *pef;
129
130 /* The domain's OS handler */
131 os_handler_t *os_hnd;
132
133 ipmi_pet_done_cb done;
134 void *cb_data;
135
136 ipmi_pet_done_cb destroy_done;
137 void *destroy_cb_data;
138
139 int in_progress;
140
141 /* The LAN configuration parameters to check. */
142 parm_check_t lanparm_check[NUM_LANPARM_SETTINGS];
143
144 /* The PEF configuration parameters to check */
145 parm_check_t pef_check[NUM_PEF_SETTINGS];
146
147 /* Timer to check the configuration periodically. */
148 pet_timer_t *timer_info;
149 os_hnd_timer_id_t *timer;
150 };
151
152 static void rescan_pet(void *cb_data, os_hnd_timer_id_t *id);
153
154 static void
pet_lock(ipmi_pet_t * pet)155 pet_lock(ipmi_pet_t *pet)
156 {
157 ipmi_lock(pet->timer_info->lock);
158 }
159
160 static void
pet_unlock(ipmi_pet_t * pet)161 pet_unlock(ipmi_pet_t *pet)
162 {
163 ipmi_unlock(pet->timer_info->lock);
164 }
165
166 static void
internal_pet_destroy(ipmi_pet_t * pet)167 internal_pet_destroy(ipmi_pet_t *pet)
168 {
169 os_handler_t *os_hnd = pet->timer_info->os_hnd;
170
171 if (pet->in_list) {
172 ipmi_domain_attr_t *attr;
173 locked_list_t *pets;
174 int rv;
175 rv = ipmi_domain_id_find_attribute(pet->domain,
176 IPMI_PET_ATTR_NAME, &attr);
177 if (!rv) {
178 pet->refcount++;
179 pet->in_list = 0;
180 pet_unlock(pet);
181
182 pets = ipmi_domain_attr_get_data(attr);
183
184 locked_list_remove(pets, pet, NULL);
185 ipmi_domain_attr_put(attr);
186 pet_lock(pet);
187 /* While we were unlocked, someone may have come in and
188 grabbed the PET by iterating the list of PETs. That's
189 ok, we just let them handle the destruction since this
190 code will not be entered again. */
191 if (pet->refcount != 1) {
192 pet->refcount--;
193 pet_unlock(pet);
194 return;
195 }
196 }
197 }
198 pet_unlock(pet);
199
200 if (os_hnd->stop_timer(os_hnd, pet->timer) == 0) {
201 ipmi_destroy_lock(pet->timer_info->lock);
202 os_hnd->free_timer(os_hnd, pet->timer);
203 ipmi_mem_free(pet->timer_info);
204 } else {
205 pet->timer_info->cancelled = 1;
206 }
207
208 if (pet->destroy_done) {
209 pet->destroy_done(pet, 0, pet->destroy_cb_data);
210 }
211
212 ipmi_mem_free(pet);
213 }
214
215 static void
pet_get_nolock(ipmi_pet_t * pet)216 pet_get_nolock(ipmi_pet_t *pet)
217 {
218 pet->refcount++;
219 }
220
221 static void
pet_get(ipmi_pet_t * pet)222 pet_get(ipmi_pet_t *pet)
223 {
224 pet_lock(pet);
225 pet_get_nolock(pet);
226 pet_unlock(pet);
227 }
228
229 /* Be very careful, only call this when the refcount cannot go to zero. */
230 static void
pet_put_nolock(ipmi_pet_t * pet)231 pet_put_nolock(ipmi_pet_t *pet)
232 {
233 pet->refcount--;
234 }
235
236 static void
pet_put_locked(ipmi_pet_t * pet)237 pet_put_locked(ipmi_pet_t *pet)
238 {
239 pet->refcount--;
240 if (pet->refcount == 0) {
241 internal_pet_destroy(pet);
242 return;
243 }
244 pet_unlock(pet);
245 }
246
247 static void
pet_put(ipmi_pet_t * pet)248 pet_put(ipmi_pet_t *pet)
249 {
250 pet_lock(pet);
251 pet_put_locked(pet);
252 }
253
254 void
ipmi_pet_ref(ipmi_pet_t * pet)255 ipmi_pet_ref(ipmi_pet_t *pet)
256 {
257 pet_get(pet);
258 }
259
260 void
ipmi_pet_deref(ipmi_pet_t * pet)261 ipmi_pet_deref(ipmi_pet_t *pet)
262 {
263 pet_put(pet);
264 }
265
266 static int
pet_attr_init(ipmi_domain_t * domain,void * cb_data,void ** data)267 pet_attr_init(ipmi_domain_t *domain, void *cb_data, void **data)
268 {
269 locked_list_t *pets;
270
271 pets = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
272 if (!pets)
273 return ENOMEM;
274
275 *data = pets;
276 return 0;
277 }
278
279 static int
destroy_pet(void * cb_data,void * item1,void * item2)280 destroy_pet(void *cb_data, void *item1, void *item2)
281 {
282 ipmi_pet_t *pet = item1;
283
284 pet_lock(pet);
285 pet->in_list = 0;
286 pet_unlock(pet);
287 return LOCKED_LIST_ITER_CONTINUE;
288 }
289
290 static void
pet_attr_destroy(void * cb_data,void * data)291 pet_attr_destroy(void *cb_data, void *data)
292 {
293 locked_list_t *pets = data;
294
295 locked_list_iterate(pets, destroy_pet, NULL);
296 locked_list_destroy(pets);
297 }
298
299 /* Must be called locked, this will unlock the PET. */
300 static void
pet_op_done(ipmi_pet_t * pet)301 pet_op_done(ipmi_pet_t *pet)
302 {
303 struct timeval timeout;
304 os_handler_t *os_hnd = pet->os_hnd;
305
306 pet->in_progress--;
307
308 if (pet->in_progress == 0) {
309 if (pet->lanparm) {
310 ipmi_lanparm_destroy(pet->lanparm, NULL, NULL);
311 pet->lanparm = NULL;
312 }
313
314 if (pet->done) {
315 ipmi_pet_done_cb done = pet->done;
316 void *cb_data = pet->cb_data;
317 pet->done = NULL;
318 pet_unlock(pet);
319 done(pet, 0, cb_data);
320 pet_lock(pet);
321 }
322
323 /* Restart the timer */
324 timeout.tv_sec = PET_TIMEOUT_SEC;
325 timeout.tv_usec = 0;
326 os_hnd->start_timer(os_hnd, pet->timer, &timeout, rescan_pet,
327 pet->timer_info);
328 pet->timer_info->running = 1;
329
330 }
331
332 pet_put_locked(pet);
333 }
334
335 static void
lanparm_unlocked(ipmi_lanparm_t * lanparm,int err,void * cb_data)336 lanparm_unlocked(ipmi_lanparm_t *lanparm,
337 int err,
338 void *cb_data)
339 {
340 ipmi_pet_t *pet = cb_data;
341
342 pet_lock(pet);
343 ipmi_lanparm_destroy(pet->lanparm, NULL, NULL);
344 pet->lanparm = NULL;
345 pet_op_done(pet);
346 }
347
348 static void
lanparm_commited(ipmi_lanparm_t * lanparm,int err,void * cb_data)349 lanparm_commited(ipmi_lanparm_t *lanparm,
350 int err,
351 void *cb_data)
352 {
353 ipmi_pet_t *pet = cb_data;
354 int rv;
355 unsigned char data[1];
356
357 pet_lock(pet);
358 if (pet->destroyed) {
359 pet_op_done(pet);
360 goto out;
361 }
362
363 /* Ignore the error, committing is optional. */
364
365 data[0] = 0; /* clear lock */
366 rv = ipmi_lanparm_set_parm(pet->lanparm, 0, data, 1,
367 lanparm_unlocked, pet);
368 if (rv) {
369 ipmi_log(IPMI_LOG_WARNING,
370 "pet.c(lanparm_commited): error clearing lock: 0x%x", rv);
371 ipmi_lanparm_destroy(pet->lanparm, NULL, NULL);
372 pet->lanparm = NULL;
373 pet_op_done(pet);
374 goto out;
375 }
376 pet_unlock(pet);
377 out:
378 return;
379 }
380
381 /* Must be called locked, this will unlock the PET. */
382 static void
lanparm_op_done(ipmi_pet_t * pet,int err)383 lanparm_op_done(ipmi_pet_t *pet, int err)
384 {
385 int rv;
386
387 /* Cheap hack, -1 means stop. */
388 if (err == -1)
389 err = 0;
390
391 pet->lanparm_err = err;
392 if (pet->lanparm_lock_broken) {
393 /* Locking is not supported. */
394 pet_op_done(pet);
395 goto out;
396 } else {
397 unsigned char data[1];
398
399 if (!pet->lanparm_err && pet->changed_lanparm) {
400 /* Don't commit if an error occurred. */
401 data[0] = 2; /* commit */
402 rv = ipmi_lanparm_set_parm(pet->lanparm, 0, data, 1,
403 lanparm_commited, pet);
404 } else {
405 data[0] = 0; /* clear lock */
406 rv = ipmi_lanparm_set_parm(pet->lanparm, 0, data, 1,
407 lanparm_unlocked, pet);
408 }
409 if (rv) {
410 ipmi_log(IPMI_LOG_WARNING,
411 "pet.c(lanparm_op_done): error clearing lock: 0x%x", rv);
412 ipmi_lanparm_destroy(pet->lanparm, NULL, NULL);
413 pet->lanparm = NULL;
414 pet_op_done(pet);
415 goto out;
416 }
417 }
418 pet_unlock(pet);
419 out:
420 return;
421 }
422
423 static void lanparm_got_config(ipmi_lanparm_t *lanparm,
424 int err,
425 unsigned char *data,
426 unsigned int data_len,
427 void *cb_data);
428
429 static int
lanparm_next_config(ipmi_pet_t * pet)430 lanparm_next_config(ipmi_pet_t *pet)
431 {
432 parm_check_t *check;
433 int rv;
434
435 pet->lanparm_check_pos++;
436 if (pet->lanparm_check_pos >= NUM_LANPARM_SETTINGS) {
437 /* Return non-zero, to end the operation. */
438 return -1;
439 }
440
441 check = &(pet->lanparm_check[pet->lanparm_check_pos]);
442
443 rv = ipmi_lanparm_get_parm(pet->lanparm,
444 check->conf_num, check->set,
445 0, lanparm_got_config, pet);
446 if (rv) {
447 ipmi_log(IPMI_LOG_WARNING,
448 "pet.c(lanparm_next_config): get err for %d: 0x%x",
449 pet->lanparm_check_pos, rv);
450 }
451
452 return rv;
453 }
454
455 static void
lanparm_set_config(ipmi_lanparm_t * lanparm,int err,void * cb_data)456 lanparm_set_config(ipmi_lanparm_t *lanparm,
457 int err,
458 void *cb_data)
459 {
460 ipmi_pet_t *pet = cb_data;
461 int rv;
462
463 pet_lock(pet);
464 if (pet->destroyed) {
465 lanparm_op_done(pet, ECANCELED);
466 goto out;
467 }
468
469 if (err) {
470 ipmi_log(IPMI_LOG_WARNING,
471 "pet.c(lanparm_set_config): set failed for %d: 0x%x",
472 pet->lanparm_check_pos, err);
473 lanparm_op_done(pet, err);
474 goto out;
475 }
476
477 rv = lanparm_next_config(pet);
478 if (rv) {
479 lanparm_op_done(pet, rv);
480 goto out;
481 }
482 pet_unlock(pet);
483 out:
484 return;
485 }
486
487 static void
lanparm_got_config(ipmi_lanparm_t * lanparm,int err,unsigned char * data,unsigned int data_len,void * cb_data)488 lanparm_got_config(ipmi_lanparm_t *lanparm,
489 int err,
490 unsigned char *data,
491 unsigned int data_len,
492 void *cb_data)
493 {
494 ipmi_pet_t *pet = cb_data;
495 unsigned char val[22];
496 int rv;
497 int pos;
498 parm_check_t *check;
499 int check_failed = 0;
500 unsigned int i;
501
502 pet_lock(pet);
503 if (pet->destroyed) {
504 lanparm_op_done(pet, ECANCELED);
505 goto out;
506 }
507
508 if (err) {
509 ipmi_log(IPMI_LOG_WARNING,
510 "pet.c(lanparm_got_config): get failed for %d: 0x%x",
511 pet->lanparm_check_pos, err);
512 lanparm_op_done(pet, err);
513 goto out;
514 }
515
516 pos = pet->lanparm_check_pos;
517 check = &(pet->lanparm_check[pos]);
518
519 /* Don't forget to skip the revision number in the length. */
520 if (data_len < (check->data_len+1)) {
521 ipmi_log(IPMI_LOG_WARNING,
522 "pet.c(lanparm_got_config): data length too short for"
523 " config %d, was %d, expected %d", check->conf_num,
524 data_len, check->data_len);
525 lanparm_op_done(pet, EINVAL);
526 goto out;
527 }
528
529 data++; /* Skip the revision number */
530
531 /* Check the config item we got and make sure it matches. If it
532 does not match, send the proper data for it. */
533 for (i=0; i<check->data_len; i++) {
534 unsigned char checkdata;
535
536 checkdata = check->data[i];
537 if ((data[i] & check->mask[i]) != checkdata) {
538 check_failed = 1;
539 break;
540 }
541 }
542
543 if (check_failed) {
544 for (i=0; i<check->data_len; i++) {
545 unsigned char checkdata;
546
547 checkdata = check->data[i];
548 val[i] = (data[i] & ~check->mask[i]) | checkdata;
549 }
550 rv = ipmi_lanparm_set_parm(pet->lanparm,
551 check->conf_num, val, check->data_len,
552 lanparm_set_config, pet);
553 if (rv) {
554 ipmi_log(IPMI_LOG_WARNING,
555 "pet.c(lanparm_got_config): sending set: 0x%x",
556 rv);
557 lanparm_op_done(pet, rv);
558 goto out;
559 }
560 pet->changed_lanparm = 1;
561 } else {
562 rv = lanparm_next_config(pet);
563 if (rv) {
564 lanparm_op_done(pet, rv);
565 goto out;
566 }
567 }
568
569 pet_unlock(pet);
570 out:
571 return;
572 }
573
574 static void
pef_unlocked(ipmi_pef_t * pef,int err,void * cb_data)575 pef_unlocked(ipmi_pef_t *pef,
576 int err,
577 void *cb_data)
578 {
579 ipmi_pet_t *pet = cb_data;
580
581 pet_lock(pet);
582 ipmi_pef_destroy(pet->pef, NULL, NULL);
583 pet->pef = NULL;
584 pet_op_done(pet);
585 }
586
587 static void
pef_commited(ipmi_pef_t * pef,int err,void * cb_data)588 pef_commited(ipmi_pef_t *pef,
589 int err,
590 void *cb_data)
591 {
592 ipmi_pet_t *pet = cb_data;
593 int rv;
594 unsigned char data[1];
595
596 pet_lock(pet);
597 if (pet->destroyed) {
598 ipmi_pef_destroy(pet->pef, NULL, NULL);
599 pet->pef = NULL;
600 pet_op_done(pet);
601 goto out;
602 }
603
604 /* Ignore the error, committing is optional. */
605
606 data[0] = 0; /* clear lock */
607 rv = ipmi_pef_set_parm(pet->pef, 0, data, 1,
608 pef_unlocked, pet);
609 if (rv) {
610 ipmi_log(IPMI_LOG_WARNING,
611 "pet.c(pef_commited): error clearing lock: 0x%x", rv);
612 ipmi_pef_destroy(pet->pef, NULL, NULL);
613 pet->pef = NULL;
614 pet_op_done(pet);
615 goto out;
616 }
617 pet_unlock(pet);
618 out:
619 return;
620 }
621
622 /* Must be called locked, this will unlock the PET. */
623 static void
pef_op_done(ipmi_pet_t * pet,int err)624 pef_op_done(ipmi_pet_t *pet, int err)
625 {
626 int rv;
627
628 /* Cheap hack, -1 means stop. */
629 if (err == -1)
630 err = 0;
631
632 pet->pef_err = err;
633 if (pet->pef_lock_broken) {
634 /* Locking is not supported. */
635 ipmi_pef_destroy(pet->pef, NULL, NULL);
636 pet->pef = NULL;
637 pet_op_done(pet);
638 goto out;
639 } else {
640 unsigned char data[1];
641
642 if (!pet->pef_err && pet->changed_pef) {
643 /* Don't commit if an error occurred. */
644 data[0] = 2; /* commit */
645 rv = ipmi_pef_set_parm(pet->pef, 0, data, 1, pef_commited, pet);
646 } else {
647 data[0] = 0; /* clear lock */
648 rv = ipmi_pef_set_parm(pet->pef, 0, data, 1, pef_unlocked, pet);
649 }
650 if (rv) {
651 ipmi_log(IPMI_LOG_WARNING,
652 "pet.c(pef_op_done): error clearing lock: 0x%x", rv);
653 pet_op_done(pet);
654 ipmi_pef_destroy(pet->pef, NULL, NULL);
655 pet->pef = NULL;
656 goto out;
657 }
658 }
659 pet_unlock(pet);
660 out:
661 return;
662 }
663
664 static void pef_got_config(ipmi_pef_t *pef,
665 int err,
666 unsigned char *data,
667 unsigned int data_len,
668 void *cb_data);
669
670 static int
pef_next_config(ipmi_pet_t * pet)671 pef_next_config(ipmi_pet_t *pet)
672 {
673 parm_check_t *check;
674 int rv;
675
676 pet->pef_check_pos++;
677 if (pet->pef_check_pos >= NUM_PEF_SETTINGS) {
678 /* Return non-zero, to end the operation. */
679 return -1;
680 }
681
682 check = &(pet->pef_check[pet->pef_check_pos]);
683
684 rv = ipmi_pef_get_parm(pet->pef, check->conf_num, check->set,
685 0, pef_got_config, pet);
686 if (rv) {
687 ipmi_log(IPMI_LOG_WARNING,
688 "pet.c(pef_next_config): PEF get err: 0x%x", rv);
689 }
690
691 return rv;
692 }
693
694 static void
pef_set_config(ipmi_pef_t * pef,int err,void * cb_data)695 pef_set_config(ipmi_pef_t *pef,
696 int err,
697 void *cb_data)
698 {
699 ipmi_pet_t *pet = cb_data;
700 int rv;
701
702 pet_lock(pet);
703 if (pet->destroyed) {
704 pef_op_done(pet, ECANCELED);
705 goto out;
706 }
707
708 if (err) {
709 ipmi_log(IPMI_LOG_WARNING,
710 "pet.c(pef_set_config): PEF set failed for %d: 0x%x",
711 pet->pef_check_pos, err);
712 pef_op_done(pet, err);
713 goto out;
714 }
715
716 rv = pef_next_config(pet);
717 if (rv) {
718 pef_op_done(pet, rv);
719 goto out;
720 }
721 pet_unlock(pet);
722 out:
723 return;
724 }
725
726 static void
pef_got_config(ipmi_pef_t * pef,int err,unsigned char * data,unsigned int data_len,void * cb_data)727 pef_got_config(ipmi_pef_t *pef,
728 int err,
729 unsigned char *data,
730 unsigned int data_len,
731 void *cb_data)
732 {
733 ipmi_pet_t *pet = cb_data;
734 unsigned char val[22];
735 int rv;
736 int pos;
737 parm_check_t *check;
738 int check_failed = 0;
739 unsigned int i;
740
741 pet_lock(pet);
742 if (pet->destroyed) {
743 pef_op_done(pet, ECANCELED);
744 goto out;
745 }
746
747 if (err) {
748 ipmi_log(IPMI_LOG_WARNING,
749 "pet.c(pef_got_control): PEF alloc failed: 0x%x", err);
750 pef_op_done(pet, err);
751 goto out;
752 }
753
754 pos = pet->pef_check_pos;
755 check = &(pet->pef_check[pos]);
756
757 /* Don't forget to skip the revision number in the length. */
758 if (data_len < check->data_len) {
759 ipmi_log(IPMI_LOG_WARNING,
760 "pet.c(pef_got_cofnfig): PEF data length too short for"
761 " config %d, was %d, expected %d", check->conf_num,
762 data_len, check->data_len);
763 pef_op_done(pet, EINVAL);
764 goto out;
765 }
766
767 data++; /* Skip the revision number */
768
769 /* Check the config item we got and make sure it matches. If it
770 does not match, send the proper data for it. */
771 for (i=0; i<check->data_len; i++) {
772 if ((data[i] & check->mask[i]) != check->data[i]) {
773 check_failed = 1;
774 break;
775 }
776 }
777
778 if (check_failed) {
779 for (i=0; i<check->data_len; i++)
780 val[i] = (data[i] & ~check->mask[i]) | check->data[i];
781 rv = ipmi_pef_set_parm(pef, check->conf_num, val, check->data_len,
782 pef_set_config, pet);
783 if (rv) {
784 ipmi_log(IPMI_LOG_WARNING,
785 "pet.c(pef_got_config): PEF error sending set: 0x%x",
786 rv);
787 pef_op_done(pet, rv);
788 goto out;
789 }
790 pet->changed_pef = 1;
791 } else {
792 rv = pef_next_config(pet);
793 if (rv) {
794 pef_op_done(pet, rv);
795 goto out;
796 }
797 }
798
799 pet_unlock(pet);
800 out:
801 return;
802 }
803
804 static void
pef_locked(ipmi_pef_t * pef,int err,void * cb_data)805 pef_locked(ipmi_pef_t *pef,
806 int err,
807 void *cb_data)
808 {
809 ipmi_pet_t *pet = cb_data;
810 int rv;
811
812 pet_lock(pet);
813 if (pet->destroyed) {
814 pef_op_done(pet, ECANCELED);
815 goto out;
816 }
817
818 if (err == 0x80) {
819 /* No support for locking, just set it so and continue. */
820 pet->pef_lock_broken = 1;
821 } else if (err) {
822 ipmi_log(IPMI_LOG_WARNING,
823 "pet.c(pef_locked): PEF lock failed: 0x%x", err);
824 pef_op_done(pet, err);
825 goto out;
826 }
827
828 /* Start the configuration process. */
829 rv = ipmi_pef_get_parm(pet->pef, pet->pef_check[0].conf_num,
830 pet->pef_check[0].set, 0,
831 pef_got_config, pet);
832 if (rv) {
833 ipmi_log(IPMI_LOG_WARNING,
834 "pet.c(pef_locked): PEF control get err: 0x%x", rv);
835 pef_op_done(pet, rv);
836 goto out;
837 }
838
839 pet_unlock(pet);
840 out:
841 return;
842 }
843
844 static void
pef_alloced(ipmi_pef_t * pef,int err,void * cb_data)845 pef_alloced(ipmi_pef_t *pef, int err, void *cb_data)
846 {
847 ipmi_pet_t *pet = cb_data;
848 unsigned char data[1];
849 int rv;
850
851 pet_lock(pet);
852 if (pet->destroyed) {
853 pef_op_done(pet, ECANCELED);
854 goto out;
855 }
856
857 if (err) {
858 ipmi_log(IPMI_LOG_WARNING,
859 "pet.c(pef_alloced): PEF alloc failed: 0x%x", err);
860 pef_op_done(pet, err);
861 goto out;
862 }
863
864 /* Start the configuration process. */
865 data[0] = 1; /* Attempt to lock */
866 rv = ipmi_pef_set_parm(pet->pef, 0, data, 1,
867 pef_locked, pet);
868 if (rv) {
869 ipmi_log(IPMI_LOG_WARNING,
870 "pet.c(pef_alloced): PEF control get err: 0x%x", rv);
871 pef_op_done(pet, rv);
872 goto out;
873 }
874
875 pet_unlock(pet);
876 out:
877 return;
878 }
879
880 static int
start_pet_setup(ipmi_mc_t * mc,ipmi_pet_t * pet)881 start_pet_setup(ipmi_mc_t *mc,
882 ipmi_pet_t *pet)
883 {
884 int rv = 0;
885
886 pet_lock(pet);
887
888 if (pet->in_progress) {
889 pet_unlock(pet);
890 return EAGAIN;
891 }
892
893 pet->pet = pet;
894 pet->pef_lock_broken = 0;
895 pet->pef_err = 0;
896 pet->changed_pef = 0;
897 pet->lanparm_lock_broken = 0;
898 pet->lanparm_err = 0;
899 pet->changed_lanparm = 0;
900
901 pet->pef_check_pos = 0;
902 pet->in_progress++;
903 pet_get_nolock(pet);
904 rv = ipmi_pef_alloc(mc, pef_alloced, pet, &pet->pef);
905 if (rv) {
906 pet->in_progress--;
907 pet_put_nolock(pet);
908 ipmi_log(IPMI_LOG_WARNING,
909 "start_pet_setup: Unable to allocate pef: 0x%x", rv);
910 goto out;
911 }
912
913 /* Now that we have the channel, set up the lan parms. */
914 pet->lanparm_check_pos = 0;
915 rv = ipmi_lanparm_alloc(mc, pet->channel, &(pet->lanparm));
916 if (rv) {
917 ipmi_log(IPMI_LOG_WARNING,
918 "start_pet_setup: Unable to allocate lanparm: 0x%x",
919 rv);
920 } else {
921 pet->in_progress++;
922 pet_get_nolock(pet);
923 rv = ipmi_lanparm_get_parm(pet->lanparm,
924 IPMI_LANPARM_DEST_TYPE,
925 pet->lan_dest_sel,
926 0,
927 lanparm_got_config,
928 pet);
929 if (rv) {
930 pet->in_progress--;
931 pet_put_nolock(pet);
932 ipmi_log(IPMI_LOG_WARNING,
933 "start_pet_setup: Unable to get dest type: 0x%x",
934 rv);
935 ipmi_lanparm_destroy(pet->lanparm, NULL, NULL);
936 pet->lanparm = NULL;
937 }
938 }
939 rv = 0; /* We continue with the PEF run, even if the lanparm fails. */
940
941 out:
942 pet_unlock(pet);
943 return rv;
944 }
945
946 int
ipmi_pet_create_mc(ipmi_mc_t * mc,unsigned int channel,struct in_addr ip_addr,unsigned char mac_addr[6],unsigned int eft_sel,unsigned int policy_num,unsigned int apt_sel,unsigned int lan_dest_sel,ipmi_pet_done_cb done,void * cb_data,ipmi_pet_t ** ret_pet)947 ipmi_pet_create_mc(ipmi_mc_t *mc,
948 unsigned int channel,
949 struct in_addr ip_addr,
950 unsigned char mac_addr[6],
951 unsigned int eft_sel,
952 unsigned int policy_num,
953 unsigned int apt_sel,
954 unsigned int lan_dest_sel,
955 ipmi_pet_done_cb done,
956 void *cb_data,
957 ipmi_pet_t **ret_pet)
958 {
959 ipmi_pet_t *pet;
960 int rv;
961 os_handler_t *os_hnd;
962 char domain_name[IPMI_MC_NAME_LEN];
963 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
964 ipmi_domain_attr_t *attr;
965 locked_list_t *pets;
966
967 rv = ipmi_domain_register_attribute(domain, IPMI_PET_ATTR_NAME,
968 pet_attr_init, pet_attr_destroy, NULL,
969 &attr);
970 if (rv)
971 return rv;
972 pets = ipmi_domain_attr_get_data(attr);
973
974 pet = ipmi_mem_alloc(sizeof(*pet));
975 if (!pet) {
976 ipmi_domain_attr_put(attr);
977 return ENOMEM;
978 }
979 memset(pet, 0, sizeof(*pet));
980
981 ipmi_domain_get_name(domain, domain_name, sizeof(domain_name));
982 snprintf(pet->name, sizeof(pet->name), "%s.%d", domain_name,
983 ipmi_domain_get_unique_num(domain));
984 pet->refcount = 1;
985 pet->in_list = 1;
986 pet->mc = ipmi_mc_convert_to_id(mc);
987 pet->domain = ipmi_domain_convert_to_id(domain);
988 pet->channel = channel;
989 pet->ip_addr = ip_addr;
990 pet->policy_num = policy_num;
991 pet->eft_sel = eft_sel;
992 pet->apt_sel = apt_sel;
993 pet->lan_dest_sel = lan_dest_sel;
994 pet->done = done;
995 pet->cb_data = cb_data;
996 memcpy(pet->mac_addr, mac_addr, sizeof(pet->mac_addr));
997 pet->in_progress = 0;
998
999 /* Set up all the data we want in the PEF and LANPARMs
1000 configuration. */
1001 pet->pef_check[0].conf_num = IPMI_PEFPARM_CONTROL;
1002 pet->pef_check[0].data_len = 1;
1003 pet->pef_check[0].data[0] = 1;
1004 pet->pef_check[0].mask[0] = 1;
1005 pet->pef_check[1].conf_num = IPMI_PEFPARM_ACTION_GLOBAL_CONTROL;
1006 pet->pef_check[1].data_len = 1;
1007 pet->pef_check[1].data[0] = 1;
1008 pet->pef_check[1].mask[0] = 1;
1009 pet->pef_check[2].conf_num = IPMI_PEFPARM_EVENT_FILTER_TABLE;
1010 pet->pef_check[2].set = eft_sel;
1011 pet->pef_check[2].data_len = 21;
1012 memset(pet->pef_check[2].data, 0xff, 10);
1013 memset(pet->pef_check[2].data+10, 0, 21-9);
1014 memset(pet->pef_check[2].mask, 0xff, 21);
1015 pet->pef_check[2].data[0] = eft_sel;
1016 pet->pef_check[2].mask[0] = 0x7f;
1017 pet->pef_check[2].data[1] = 0x80;
1018 pet->pef_check[2].mask[1] = 0x80;
1019 pet->pef_check[2].data[2] = 0x01;
1020 pet->pef_check[2].mask[2] = 0x3f;
1021 pet->pef_check[2].data[3] = policy_num;
1022 pet->pef_check[2].mask[3] = 0x0f;
1023 pet->pef_check[2].data[4] = 0;
1024 pet->pef_check[2].data[10] = 0xff;
1025 pet->pef_check[2].data[11] = 0xff;
1026 pet->pef_check[3].conf_num = IPMI_PEFPARM_ALERT_POLICY_TABLE;
1027 pet->pef_check[3].set = apt_sel;
1028 pet->pef_check[3].data_len = 4;
1029 pet->pef_check[3].data[0] = apt_sel;
1030 pet->pef_check[3].mask[0] = 0x7f;
1031 pet->pef_check[3].data[1] = 0x08 | (policy_num << 4);
1032 pet->pef_check[3].mask[1] = 0xff;
1033 pet->pef_check[3].data[2] = (channel << 4) | lan_dest_sel;
1034 pet->pef_check[3].mask[2] = 0xff;
1035 pet->pef_check[3].data[3] = 0;
1036 pet->pef_check[3].mask[3] = 0xff;
1037
1038 pet->lanparm_check[0].conf_num = IPMI_LANPARM_DEST_TYPE;
1039 pet->lanparm_check[0].set = lan_dest_sel;
1040 pet->lanparm_check[0].data_len = 4;
1041 pet->lanparm_check[0].data[0] = lan_dest_sel;
1042 pet->lanparm_check[0].mask[0] = 0x0f;
1043 pet->lanparm_check[0].data[1] = 0x80;
1044 pet->lanparm_check[0].mask[1] = 0x87;
1045 pet->lanparm_check[0].data[2] = IPMI_LANPARM_DEFAULT_ALERT_RETRY_TIMEOUT;
1046 pet->lanparm_check[0].mask[2] = 0xff;
1047 pet->lanparm_check[0].data[3] = IPMI_LANPARM_DEFAULT_ALERT_RETRIES;
1048 pet->lanparm_check[0].mask[3] = 0x07;
1049 pet->lanparm_check[1].conf_num = IPMI_LANPARM_DEST_ADDR;
1050 pet->lanparm_check[1].set = lan_dest_sel;
1051 pet->lanparm_check[1].data_len = 13;
1052 pet->lanparm_check[1].data[0] = lan_dest_sel;
1053 pet->lanparm_check[1].mask[0] = 0x0f;
1054 pet->lanparm_check[1].data[1] = 0x00;
1055 pet->lanparm_check[1].mask[1] = 0xf0;
1056 pet->lanparm_check[1].data[2] = 0x00;
1057 pet->lanparm_check[1].mask[2] = 0x01;
1058 memset(pet->lanparm_check[1].mask+3, 0xff, 10);
1059 memcpy(pet->lanparm_check[1].data+3, &ip_addr, 4);
1060 memcpy(pet->lanparm_check[1].data+7, mac_addr, 6);
1061
1062 os_hnd = ipmi_domain_get_os_hnd(domain);
1063 pet->os_hnd = os_hnd;
1064
1065 /* Start a timer for this PET to periodically check it. */
1066 pet->timer_info = ipmi_mem_alloc(sizeof(*(pet->timer_info)));
1067 if (!pet->timer_info) {
1068 rv = ENOMEM;
1069 goto out_err;
1070 }
1071 pet->timer_info->cancelled = 0;
1072 pet->timer_info->os_hnd = os_hnd;
1073 pet->timer_info->pet = pet;
1074 pet->timer_info->running = 0;
1075 pet->timer_info->lock = NULL;
1076 rv = os_hnd->alloc_timer(os_hnd, &pet->timer);
1077 if (rv)
1078 goto out_err;
1079
1080 rv = ipmi_create_lock_os_hnd(os_hnd, &pet->timer_info->lock);
1081 if (rv)
1082 goto out_err;
1083
1084 if (! locked_list_add(pets, pet, NULL)) {
1085 rv = ENOMEM;
1086 goto out_err;
1087 }
1088
1089 ipmi_domain_attr_put(attr);
1090
1091 rv = start_pet_setup(mc, pet);
1092 if (rv)
1093 goto out_err;
1094
1095 if (ret_pet)
1096 *ret_pet = pet;
1097
1098 return 0;
1099
1100 out_err:
1101 locked_list_remove(pets, pet, NULL);
1102 ipmi_domain_attr_put(attr);
1103 if (pet->timer_info) {
1104 if (pet->timer) {
1105 if (os_hnd->stop_timer(os_hnd, pet->timer) == 0) {
1106 if (pet->timer_info->lock)
1107 ipmi_destroy_lock(pet->timer_info->lock);
1108 os_hnd->free_timer(os_hnd, pet->timer);
1109 ipmi_mem_free(pet->timer_info);
1110 } else {
1111 pet->timer_info->cancelled = 1;
1112 }
1113 } else
1114 ipmi_mem_free(pet->timer_info);
1115 }
1116 ipmi_mem_free(pet);
1117 return rv;
1118 }
1119
1120 int
ipmi_pet_create(ipmi_domain_t * domain,unsigned int connection,unsigned int channel,struct in_addr ip_addr,unsigned char mac_addr[6],unsigned int eft_sel,unsigned int policy_num,unsigned int apt_sel,unsigned int lan_dest_sel,ipmi_pet_done_cb done,void * cb_data,ipmi_pet_t ** ret_pet)1121 ipmi_pet_create(ipmi_domain_t *domain,
1122 unsigned int connection,
1123 unsigned int channel,
1124 struct in_addr ip_addr,
1125 unsigned char mac_addr[6],
1126 unsigned int eft_sel,
1127 unsigned int policy_num,
1128 unsigned int apt_sel,
1129 unsigned int lan_dest_sel,
1130 ipmi_pet_done_cb done,
1131 void *cb_data,
1132 ipmi_pet_t **ret_pet)
1133 {
1134 ipmi_system_interface_addr_t si;
1135 ipmi_mc_t *mc;
1136 int rv;
1137
1138 si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1139 si.channel = connection;
1140 si.lun = 0;
1141
1142 mc = i_ipmi_find_mc_by_addr(domain, (ipmi_addr_t *) &si, sizeof(si));
1143 if ((!mc) && (connection == 0)) {
1144 /* If the specific connection doesn't exist and the connection
1145 is 0, use the BMC channel. */
1146 si.channel = IPMI_BMC_CHANNEL;
1147 mc = i_ipmi_find_mc_by_addr(domain, (ipmi_addr_t *) &si,
1148 sizeof(si));
1149 }
1150
1151 if (!mc)
1152 return EINVAL;
1153
1154 rv = ipmi_pet_create_mc(mc,
1155 channel,
1156 ip_addr,
1157 mac_addr,
1158 eft_sel,
1159 policy_num,
1160 apt_sel,
1161 lan_dest_sel,
1162 done,
1163 cb_data,
1164 ret_pet);
1165 i_ipmi_mc_put(mc);
1166
1167 return rv;
1168 }
1169
1170 static void
rescan_pet_mc(ipmi_mc_t * mc,void * cb_data)1171 rescan_pet_mc(ipmi_mc_t *mc, void *cb_data)
1172 {
1173 pet_timer_t *timer_info = cb_data;
1174 ipmi_pet_t *pet = timer_info->pet;
1175
1176 timer_info->err = start_pet_setup(mc, pet);
1177 }
1178
1179 static void
rescan_pet(void * cb_data,os_hnd_timer_id_t * id)1180 rescan_pet(void *cb_data, os_hnd_timer_id_t *id)
1181 {
1182 pet_timer_t *timer_info = cb_data;
1183 ipmi_pet_t *pet;
1184 int rv;
1185 struct timeval timeout;
1186
1187 ipmi_lock(timer_info->lock);
1188 if (timer_info->cancelled) {
1189 ipmi_unlock(timer_info->lock);
1190 timer_info->os_hnd->free_timer(timer_info->os_hnd, id);
1191 ipmi_destroy_lock(timer_info->lock);
1192 ipmi_mem_free(timer_info);
1193 return;
1194 }
1195 pet = timer_info->pet;
1196 pet->timer_info->running = 0;
1197 pet_get(pet);
1198
1199 timer_info->err = 0;
1200 rv = ipmi_mc_pointer_cb(pet->mc, rescan_pet_mc, timer_info);
1201 if (!rv)
1202 rv = timer_info->err;
1203
1204 if (rv) {
1205 os_handler_t *os_hnd = timer_info->os_hnd;
1206 /* Got an error, just restart the timer */
1207 timeout.tv_sec = PET_TIMEOUT_SEC;
1208 timeout.tv_usec = 0;
1209 os_hnd->start_timer(os_hnd, pet->timer, &timeout, rescan_pet,
1210 pet->timer_info);
1211 pet->timer_info->running = 1;
1212 }
1213
1214 ipmi_unlock(timer_info->lock);
1215 }
1216
1217 int
ipmi_pet_destroy(ipmi_pet_t * pet,ipmi_pet_done_cb done,void * cb_data)1218 ipmi_pet_destroy(ipmi_pet_t *pet,
1219 ipmi_pet_done_cb done,
1220 void *cb_data)
1221
1222 {
1223 pet_lock(pet);
1224 if (pet->in_list) {
1225 ipmi_domain_attr_t *attr;
1226 locked_list_t *pets;
1227 int rv;
1228
1229 pet->in_list = 0;
1230 rv = ipmi_domain_id_find_attribute(pet->domain,
1231 IPMI_PET_ATTR_NAME, &attr);
1232 if (!rv) {
1233 pet_unlock(pet);
1234
1235 pets = ipmi_domain_attr_get_data(attr);
1236
1237 locked_list_remove(pets, pet, NULL);
1238 ipmi_domain_attr_put(attr);
1239 pet_lock(pet);
1240 }
1241 }
1242
1243 pet->destroyed = 1;
1244 pet->destroy_done = done;
1245 pet->destroy_cb_data = cb_data;
1246 pet_unlock(pet);
1247
1248 pet_put(pet);
1249 return 0;
1250 }
1251
1252 int
ipmi_pet_get_name(ipmi_pet_t * pet,char * name,int length)1253 ipmi_pet_get_name(ipmi_pet_t *pet, char *name, int length)
1254 {
1255 int slen;
1256
1257 if (length <= 0)
1258 return 0;
1259
1260 /* Never changes, no lock needed. */
1261 slen = strlen(pet->name);
1262 if (slen == 0) {
1263 if (name)
1264 *name = '\0';
1265 goto out;
1266 }
1267
1268 if (name) {
1269 memcpy(name, pet->name, slen);
1270 name[slen] = '\0';
1271 }
1272 out:
1273 return slen;
1274 }
1275
1276 typedef struct iterate_pets_info_s
1277 {
1278 ipmi_pet_ptr_cb handler;
1279 void *cb_data;
1280 } iterate_pets_info_t;
1281
1282 static int
pets_handler(void * cb_data,void * item1,void * item2)1283 pets_handler(void *cb_data, void *item1, void *item2)
1284 {
1285 iterate_pets_info_t *info = cb_data;
1286 info->handler(item1, info->cb_data);
1287 pet_put(item1);
1288 return LOCKED_LIST_ITER_CONTINUE;
1289 }
1290
1291 static int
pets_prefunc(void * cb_data,void * item1,void * item2)1292 pets_prefunc(void *cb_data, void *item1, void *item2)
1293 {
1294 pet_get(item1);
1295 return LOCKED_LIST_ITER_CONTINUE;
1296 }
1297
1298 void
ipmi_pet_iterate_pets(ipmi_domain_t * domain,ipmi_pet_ptr_cb handler,void * cb_data)1299 ipmi_pet_iterate_pets(ipmi_domain_t *domain,
1300 ipmi_pet_ptr_cb handler,
1301 void *cb_data)
1302 {
1303 iterate_pets_info_t info;
1304 ipmi_domain_attr_t *attr;
1305 locked_list_t *pets;
1306 int rv;
1307
1308 rv = ipmi_domain_find_attribute(domain, IPMI_PET_ATTR_NAME,
1309 &attr);
1310 if (rv)
1311 return;
1312 pets = ipmi_domain_attr_get_data(attr);
1313
1314 info.handler = handler;
1315 info.cb_data = cb_data;
1316 locked_list_iterate_prefunc(pets, pets_prefunc, pets_handler, &info);
1317 ipmi_domain_attr_put(attr);
1318 }
1319
1320 ipmi_mcid_t
ipmi_pet_get_mc_id(ipmi_pet_t * pet)1321 ipmi_pet_get_mc_id(ipmi_pet_t *pet)
1322 {
1323 return pet->mc;
1324 }
1325
1326 unsigned int
ipmi_pet_get_channel(ipmi_pet_t * pet)1327 ipmi_pet_get_channel(ipmi_pet_t *pet)
1328 {
1329 return pet->channel;
1330 }
1331
1332 struct in_addr *
ipmi_pet_get_ip_addr(ipmi_pet_t * pet,struct in_addr * ip_addr)1333 ipmi_pet_get_ip_addr(ipmi_pet_t *pet, struct in_addr *ip_addr)
1334 {
1335 memcpy(ip_addr, &pet->ip_addr, sizeof(*ip_addr));
1336 return ip_addr;
1337 }
1338
1339 unsigned char *
ipmi_pet_get_mac_addr(ipmi_pet_t * pet,unsigned char mac_addr[6])1340 ipmi_pet_get_mac_addr(ipmi_pet_t *pet, unsigned char mac_addr[6])
1341 {
1342 memcpy(mac_addr, pet->mac_addr, 6);
1343 return mac_addr;
1344 }
1345
1346 unsigned int
ipmi_pet_get_eft_sel(ipmi_pet_t * pet)1347 ipmi_pet_get_eft_sel(ipmi_pet_t *pet)
1348 {
1349 return pet->eft_sel;
1350 }
1351
1352 unsigned int
ipmi_pet_get_policy_num(ipmi_pet_t * pet)1353 ipmi_pet_get_policy_num(ipmi_pet_t *pet)
1354 {
1355 return pet->policy_num;
1356 }
1357
1358 unsigned int
ipmi_pet_get_apt_sel(ipmi_pet_t * pet)1359 ipmi_pet_get_apt_sel(ipmi_pet_t *pet)
1360 {
1361 return pet->apt_sel;
1362 }
1363
1364 unsigned int
ipmi_pet_get_lan_dest_sel(ipmi_pet_t * pet)1365 ipmi_pet_get_lan_dest_sel(ipmi_pet_t *pet)
1366 {
1367 return pet->lan_dest_sel;
1368 }
1369