1 /* $OpenBSD: notification.c,v 1.9 2011/01/20 23:12:33 jasper Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/uio.h> 22 23 #include <netinet/in.h> 24 #include <netinet/in_systm.h> 25 #include <netinet/ip.h> 26 #include <arpa/inet.h> 27 #include <net/if_dl.h> 28 #include <unistd.h> 29 30 #include <errno.h> 31 #include <event.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include "ldpd.h" 36 #include "ldp.h" 37 #include "log.h" 38 #include "ldpe.h" 39 40 int gen_status_tlv(struct ibuf *, u_int32_t, u_int32_t, u_int32_t); 41 42 void 43 send_notification_nbr(struct nbr *nbr, u_int32_t status, u_int32_t msgid, 44 u_int32_t type) 45 { 46 struct ibuf *buf; 47 48 if (nbr->iface->passive) 49 return; 50 51 buf = send_notification(status, nbr->iface, msgid, type); 52 evbuf_enqueue(&nbr->wbuf, buf); 53 } 54 55 struct ibuf * 56 send_notification(u_int32_t status, struct iface *iface, u_int32_t msgid, 57 u_int32_t type) 58 { 59 struct ibuf *buf; 60 u_int16_t size; 61 62 if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) 63 fatal("send_notification"); 64 65 size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + STATUS_SIZE; 66 67 gen_ldp_hdr(buf, iface, size); 68 69 size -= LDP_HDR_SIZE; 70 71 gen_msg_tlv(buf, MSG_TYPE_NOTIFICATION, size); 72 73 size -= sizeof(struct ldp_msg); 74 75 gen_status_tlv(buf, status, msgid, type); 76 77 return (buf); 78 } 79 80 int 81 recv_notification(struct nbr *nbr, char *buf, u_int16_t len) 82 { 83 struct ldp_msg not; 84 struct status_tlv st; 85 86 log_debug("recv_notification: neighbor ID %s", inet_ntoa(nbr->id)); 87 88 bcopy(buf, ¬, sizeof(not)); 89 90 buf += sizeof(struct ldp_msg); 91 len -= sizeof(struct ldp_msg); 92 93 if (len < STATUS_SIZE) { 94 session_shutdown(nbr, S_BAD_MSG_LEN, not.msgid, not.type); 95 return (-1); 96 } 97 bcopy(buf, &st, sizeof(st)); 98 99 if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_LEN || 100 ntohs(st.length) > len - TLV_HDR_LEN) { 101 session_shutdown(nbr, S_BAD_TLV_LEN, not.msgid, not.type); 102 return (-1); 103 } 104 105 /* TODO optional parameters: ext status, returned PDU and msg */ 106 107 if (st.status_code & htonl(STATUS_FATAL)) 108 log_warnx("received notification from neighbor %s: %s", 109 inet_ntoa(nbr->id), 110 notification_name(ntohl(st.status_code))); 111 else 112 log_debug("received non-fatal notification from neighbor " 113 "%s: %s", inet_ntoa(nbr->id), 114 notification_name(ntohl(st.status_code))); 115 116 if (st.status_code & htonl(STATUS_FATAL)) { 117 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); 118 return (-1); 119 } 120 /* XXX in some cases we should inform the RDE about non-fatal ones */ 121 122 return (ntohs(not.length)); 123 } 124 125 int 126 gen_status_tlv(struct ibuf *buf, u_int32_t status, u_int32_t msgid, 127 u_int32_t type) 128 { 129 struct status_tlv st; 130 131 bzero(&st, sizeof(st)); 132 133 st.type = htons(TLV_TYPE_STATUS); 134 st.length = htons(STATUS_TLV_LEN); 135 st.status_code = htonl(status); 136 137 st.msg_id = msgid; 138 st.msg_type = type; 139 140 return (ibuf_add(buf, &st, STATUS_SIZE)); 141 } 142