⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ospf_packet.c

📁 router source code for the ospdf.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * OSPF Sending and Receiving OSPF Packets. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING.  If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <zebra.h>#include "thread.h"#include "memory.h"#include "linklist.h"#include "prefix.h"#include "if.h"#include "table.h"#include "sockunion.h"#include "stream.h"#include "log.h"#include "md5-gnu.h"#include "ospfd/ospfd.h"#include "ospfd/ospf_network.h"#include "ospfd/ospf_interface.h"#include "ospfd/ospf_ism.h"#include "ospfd/ospf_asbr.h"#include "ospfd/ospf_lsa.h"#include "ospfd/ospf_lsdb.h"#include "ospfd/ospf_neighbor.h"#include "ospfd/ospf_nsm.h"#include "ospfd/ospf_packet.h"#include "ospfd/ospf_spf.h"#include "ospfd/ospf_flood.h"#include "ospfd/ospf_dump.h"static void ospf_ls_ack_send_list (struct ospf_interface *, list,				   struct in_addr);/* Packet Type String. */char *ospf_packet_type_str[] ={  "unknown",  "Hello",  "Database Description",  "Link State Request",  "Link State Update",  "Link State Acknowledgment",};extern int in_cksum (void *ptr, int nbytes);/* OSPF authentication checking function */intospf_auth_type (struct ospf_interface *oi){  int auth_type;  if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET)    auth_type = oi->area->auth_type;  else    auth_type = OSPF_IF_PARAM (oi, auth_type);  /* Handle case where MD5 key list is not configured aka Cisco */  if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC &&      list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))    return OSPF_AUTH_NULL;    return auth_type;}/* forward output pointer. */voidospf_output_forward (struct stream *s, int size){  s->putp += size;}struct ospf_packet *ospf_packet_new (size_t size){  struct ospf_packet *new;  new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet));  new->s = stream_new (size);  return new;}voidospf_packet_free (struct ospf_packet *op){  if (op->s)    stream_free (op->s);  XFREE (MTYPE_OSPF_PACKET, op);  op = NULL;}struct ospf_fifo *ospf_fifo_new (){  struct ospf_fifo *new;  new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo));  return new;}/* Add new packet to fifo. */voidospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op){  if (fifo->tail)    fifo->tail->next = op;  else    fifo->head = op;  fifo->tail = op;  fifo->count++;}/* Delete first packet from fifo. */struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *fifo){  struct ospf_packet *op;  op = fifo->head;  if (op)    {      fifo->head = op->next;      if (fifo->head == NULL)	fifo->tail = NULL;      fifo->count--;    }  return op;}/* Return first fifo entry. */struct ospf_packet *ospf_fifo_head (struct ospf_fifo *fifo){  return fifo->head;}/* Flush ospf packet fifo. */voidospf_fifo_flush (struct ospf_fifo *fifo){  struct ospf_packet *op;  struct ospf_packet *next;  for (op = fifo->head; op; op = next)    {      next = op->next;      ospf_packet_free (op);    }  fifo->head = fifo->tail = NULL;  fifo->count = 0;}/* Free ospf packet fifo. */voidospf_fifo_free (struct ospf_fifo *fifo){  ospf_fifo_flush (fifo);  XFREE (MTYPE_OSPF_FIFO, fifo);}voidospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op){  /* Add packet to end of queue. */  ospf_fifo_push (oi->obuf, op);  /* Debug of packet fifo*/  /* ospf_fifo_debug (oi->obuf); */}voidospf_packet_delete (struct ospf_interface *oi){  struct ospf_packet *op;    op = ospf_fifo_pop (oi->obuf);  if (op)    ospf_packet_free (op);}struct stream *ospf_stream_copy (struct stream *new, struct stream *s){  new->endp = s->endp;  new->putp = s->putp;  new->getp = s->getp;  memcpy (new->data, s->data, stream_get_endp (s));  return new;}struct ospf_packet *ospf_packet_dup (struct ospf_packet *op){  struct ospf_packet *new;  if (stream_get_endp(op->s) != op->length)    zlog_warn ("ospf_packet_dup stream %ld ospf_packet %d size mismatch",	       STREAM_SIZE(op->s), op->length);  /* Reserve space for MD5 authentication that may be added later. */  new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);  ospf_stream_copy (new->s, op->s);  new->dst = op->dst;  new->length = op->length;  return new;}intospf_packet_max (struct ospf_interface *oi){  int max;  if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)    max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88;  else    max = oi->ifp->mtu - 88;  return max;}intospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,                       u_int16_t length){  void *ibuf;  struct md5_ctx ctx;  unsigned char digest[OSPF_AUTH_MD5_SIZE];  unsigned char *pdigest;  struct crypt_key *ck;  struct ospf_header *ospfh;  struct ospf_neighbor *nbr;    ibuf = STREAM_PNT (s);  ospfh = (struct ospf_header *) ibuf;  /* Get pointer to the end of the packet. */  pdigest = ibuf + length;  /* Get secret key. */  ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),			      ospfh->u.crypt.key_id);  if (ck == NULL)    {      zlog_warn ("interface %s: ospf_check_md5 no key %d",		 IF_NAME (oi), ospfh->u.crypt.key_id);      return 0;    }  /* check crypto seqnum. */  nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id);  if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum))    {      zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)",		 IF_NAME (oi),		 ntohl(ospfh->u.crypt.crypt_seqnum),		 ntohl(nbr->crypt_seqnum));      return 0;    }        /* Generate a digest for the ospf packet - their digest + our digest. */  md5_init_ctx (&ctx);  md5_process_bytes (ibuf, length, &ctx);  md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx);  md5_finish_ctx (&ctx, digest);  /* compare the two */  if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE))    {      zlog_warn ("interface %s: ospf_check_md5 checksum mismatch",		 IF_NAME (oi));      return 0;    }  /* save neighbor's crypt_seqnum */  if (nbr)    nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;  return 1;}/* This function is called from ospf_write(), it will detect the   authentication scheme and if it is MD5, it will change the sequence   and update the MD5 digest. */intospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op){  struct ospf_header *ospfh;  unsigned char digest[OSPF_AUTH_MD5_SIZE];  struct md5_ctx ctx;  void *ibuf;  unsigned long oldputp;  u_int32_t t;  struct crypt_key *ck;  char *auth_key;  ibuf = STREAM_DATA (op->s);  ospfh = (struct ospf_header *) ibuf;  if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)    return 0;  /* We do this here so when we dup a packet, we don't have to     waste CPU rewriting other headers. */  t = (time(NULL) & 0xFFFFFFFF);  oi->crypt_seqnum = ( t > oi->crypt_seqnum ? t : oi->crypt_seqnum++);  ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum);   /* Get MD5 Authentication key from auth_key list. */  if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))    auth_key = "";  else    {      ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);      auth_key = ck->auth_key;    }  /* Generate a digest for the entire packet + our secret key. */  md5_init_ctx (&ctx);  md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx);  md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx);  md5_finish_ctx (&ctx, digest);  /* Append md5 digest to the end of the stream. */  oldputp = stream_get_putp (op->s);  stream_set_putp (op->s, ntohs (ospfh->length));  stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE);  stream_set_putp (op->s, oldputp);  /* We do *NOT* increment the OSPF header length. */  op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE;  if (stream_get_endp(op->s) != op->length)    zlog_warn("ospf_make_md5_digest: length mismatch stream %ld ospf_packet %d", stream_get_endp(op->s), op->length);  return OSPF_AUTH_MD5_SIZE;}intospf_ls_req_timer (struct thread *thread){  struct ospf_neighbor *nbr;  nbr = THREAD_ARG (thread);  nbr->t_ls_req = NULL;  /* Send Link State Request. */  if (ospf_ls_request_count (nbr))    ospf_ls_req_send (nbr);  /* Set Link State Request retransmission timer. */  OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);  return 0;}voidospf_ls_req_event (struct ospf_neighbor *nbr){  if (nbr->t_ls_req)    {      thread_cancel (nbr->t_ls_req);      nbr->t_ls_req = NULL;    }  nbr->t_ls_req = thread_add_event (master, ospf_ls_req_timer, nbr, 0);}/* Cyclic timer function.  Fist registered in ospf_nbr_new () in   ospf_neighbor.c  */intospf_ls_upd_timer (struct thread *thread){  struct ospf_neighbor *nbr;  nbr = THREAD_ARG (thread);  nbr->t_ls_upd = NULL;  /* Send Link State Update. */  if (ospf_ls_retransmit_count (nbr) > 0)    {      list update;      struct ospf_lsdb *lsdb;      int i;      struct timeval now;      int retransmit_interval;      gettimeofday (&now, NULL);      retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval);      lsdb = &nbr->ls_rxmt;      update = list_new ();      for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)	{	  struct route_table *table = lsdb->type[i].db;	  struct route_node *rn;	  	  for (rn = route_top (table); rn; rn = route_next (rn))	    {	      struct ospf_lsa *lsa;	      	      if ((lsa = rn->info) != NULL)		/* Don't retransmit an LSA if we received it within		  the last RxmtInterval seconds - this is to allow the		  neighbour a chance to acknowledge the LSA as it may		  have ben just received before the retransmit timer		  fired.  This is a small tweak to what is in the RFC,		  but it will cut out out a lot of retransmit traffic		  - MAG */		if (tv_cmp (tv_sub (now, lsa->tv_recv), 			    int2tv (retransmit_interval)) >= 0)		  listnode_add (update, rn->info);	    }	}      if (listcount (update) > 0)	ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT);      list_delete (update);    }  /* Set LS Update retransmission timer. */  OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);  return 0;}intospf_ls_ack_timer (struct thread *thread){  struct ospf_interface *oi;  oi = THREAD_ARG (thread);  oi->t_ls_ack = NULL;  /* Send Link State Acknowledgment. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -