分类目录归档:LINUX C & ARM & C51

购入jlink 自制 转接线

晕菜到家了,买了jlink没买转换板,发的6410的版是2.0间距的10p的口,在淘宝上买板,这不是放假人家不发货,而且还没线卖,我要板没线还是用不了。一气之下,自己做了一条转换线。10p FC头,是以前买来做jtag线用的,20p fc头没有,用的dma33的ide线的头,拆了,锯开,打磨,用502粘上的,10p 2.54转2.0是用从老的磨托罗拉的BP机的板子上拆下来的单排母口做的,哈哈。接口定义如下,上图.留给有用的朋友

 

s3c_6410(亚嵌发的那个)
1  VDD_IO  电源 3.3V(输入)
2  VDD_IO  电源 3.3V(输入)
3  TRSTn  TRSTn 
4  nRESET  nRESET
5  TDI  TDI 
6  TDO  TDO
7  TMS  TMS 
8  GND  地
9  TCK  TCK 
10  GND  地

jlink v8 (20PIN)
1  vref
2  vcc(VTARGET)
3  TRST_N
5  TDI
7  TMS
9  TCK
11 RTCK
13 TDO
15 SRST_N
17 DBGRQ(Wiggler)
19 DBGACK(Wiggler)
other: GND

转换关系
jlink 20 -> 10pin
1  1 (1,2连在一起)
2  2 (1,2连在一起)
3  3
5  5
7  7
8  8
9  9
10 10
15 4
13 6

由于开发板的p1,p2本来就是连在一起的,所以1->1,2->2就行了

 

SEGGER J-Link Commander V4.26b ('?' for help)
Compiled May 20 2011 17:18:29
DLL version V4.26b, compiled May 20 2011 17:18:15
Firmware: J-Link ARM V8 compiled Apr 27 2011 20:42:35
Hardware: V8.00
S/N: 20100214
Feature(s): RDI,FlashDL,FlashBP,JFlash,GDBFull
VTarget = 3.248V
Info: TotalIRLen = 9, IRPrint = 0x0011
Found 2 JTAG devices, Total IRLen = 5:
 #0 Id: 0x2B900F0F, IRLen: 04, IRPrint: 0x0, ARM ETB
 #1 Id: 0x07B76F0F, IRLen: 05, IRPrint: 0x1, ARM1176 Core
ARM11 identified.
JTAG speed: 100 kHz
J-Link>

ARP 功击与抓包代码

上课的地方arp横行,总是上不去网。
研究了一下arp功击的代码。总用更高的频率来解决功击网关的问题,失败告终。

抓包

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

void print_arp(unsigned char *a,int len)
{
 int i;
 char ccc='1';
 for(i=0;i<len;i++){
  if(i==6 || i==12 || i==14 || i==16 || i==18 || i==19 || i==20 || i==22 || i==28 || i==32 || i==38 || i==42)
   putchar('|');
  if((i>=28 && i<=31) || (i>=38 && i<=41))
   printf("%d.",a[i]);
  else
   printf("%02x",a[i]);
  //fflush(stdout);
 }
 putchar('n');
}
void print_eth(unsigned char *a,int len)
{
 int i;
 for(i=0;i<len;i++){
  printf("%02x",a[i]);
 }
 putchar('n');
}

int set_promisc(char *interface, int fd) {
 struct ifreq ifr;
 strcpy(ifr.ifr_name, interface);
 if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
  perror("iotcl()");
  return -1;
 }
 ifr.ifr_flags |= IFF_PROMISC;
 if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
  perror("iotcl()");
  return -1;
 }
 return 0;
}

int main(int argc, char **argv) {
 int sock, n;
 unsigned char buffer[2048];
 unsigned char *iphead, *ethhead;
 struct sockaddr_ll sll;

 // if(argc != 3){
 //  printf("need interface name and protocol as argumentsn");
 //  return -1;
 // }

 if ( (sock=socket(PF_PACKET, SOCK_RAW,
     htons(ETH_P_ARP)))<0) {
  perror("socket");
  exit(1);
 }
 sll.sll_family = PF_PACKET;
 //    sll.sll_ifindex = Get_IfaceIndex(sock,argv[1]); //通过此处传入网络设备接口
 struct ifreq ifstruct;
 strcpy(ifstruct.ifr_name, "eth0");
 //sll.sll_protocol = htons(atoi(argv[2]));
 sll.sll_protocol=htons(ETH_P_ARP);

 if(bind(sock,(struct sockaddr *)(&sll),sizeof(sll))==-1)
 {
  printf("bind error:%s !n",strerror(errno));
  return -1;
 }

 //int set_promisc(char *interface, int fd) {
 if(set_promisc("eth0",sock) == -1)
 {
  printf("BLUE set promisc failed !n");
  return -1;
 }

 while (1) {
  printf("—–recive start—–n");
  n = recvfrom(sock,buffer,2048,0,NULL,NULL);
  printf("%d bytes readn",n);
  printf("index:%dn",sll.sll_ifindex );
  /* Check to see if the packet contains at least
   * complete Ethernet (14), IP (20) and TCP/UDP
   * (8) headers.
   */
  if (n<42) {
   perror("recvfrom():");
   printf("Incomplete packet (errno is %d)n",
     errno);
   close(sock);
   exit(0);
  }

  ethhead = buffer;
  printf("Destination MAC address: "
    "%02x:%02x:%02x:%02x:%02x:%02xn",
    ethhead[0],ethhead[1],ethhead[2],
    ethhead[3],ethhead[4],ethhead[5]);
  printf("Source MAC address: "
    "%02x:%02x:%02x:%02x:%02x:%02xn",
    ethhead[6],ethhead[7],ethhead[8],
    ethhead[9],ethhead[10],ethhead[11]);
  printf("protocal:"
    "0x%02x%02xn",ethhead[12],ethhead[13]);

  iphead = buffer+14; /* Skip Ethernet header */
  if (*iphead==0x45) { /* Double check for IPv4
          * and no options present */
   printf("Source host %d.%d.%d.%dn",
     iphead[12],iphead[13],
     iphead[14],iphead[15]);
   printf("Dest host %d.%d.%d.%dn",
     iphead[16],iphead[17],
     iphead[18],iphead[19]);
   printf("Source,Dest ports %d,%dn",
     (iphead[20]<<8)+iphead[21],
     (iphead[22]<<8)+iphead[23]);
   printf("Layer-4 protocol %dn",iphead[9]);
  }
  //print_eth(1,buffer,512);
  print_arp(ethhead,48);
  //  print_eth(ethhead,n);
 }

}
 

功击

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

void print_eth(unsigned char *a,int len)
{
 int i;
 for(i=0;i<len;i++){
  printf("%02x",a[i]);
 }
 putchar('n');
}
int set_promisc(char *interface, int fd) {
 struct ifreq ifr;
 strcpy(ifr.ifr_name, interface);
 if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
  perror("iotcl()");
  return -1;
 }
 ifr.ifr_flags |= IFF_PROMISC;
 if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
  perror("iotcl()");
  return -1;
 }
 return 0;
}

int main(int argc, char **argv){
 int sock;
 char SendBuffer[64];
 char intfname[16];
 struct sockaddr_ll dest;
 struct sockaddr_ll sll;

 memset(&dest,0,sizeof(dest));
 memset(&sll,0,sizeof(sll));
 strcpy(intfname,argv[1]);
 dest.sll_family=AF_PACKET;
 dest.sll_protocol=htons(ETH_P_ALL);
 if ( (sock=socket(PF_PACKET, SOCK_RAW,
     htons(ETH_P_ALL)))<0) {
  perror("socket");
  exit(1);
 }

 sll.sll_family = AF_PACKET;
 // sll.sll_ifindex = Get_IfaceIndex(sock,intfname);
 struct ifreq ifstruct;
 strcpy(ifstruct.ifr_name, "eth0");
 sll.sll_protocol = htons(ETH_P_ALL);
 dest.sll_ifindex =sll.sll_ifindex;
 dest.sll_halen = 6;
 memcpy((char*)dest.sll_addr,SendBuffer,6);

 if(bind(sock,(struct sockaddr *)(&sll),sizeof(sll))==-1)
 {
  printf("bind error!!n");
  return 0;
 }

 if(set_promisc("eth0",sock) == -1)
 {
  printf("BLUE set promisc failed !n");
  return 0;
 }

 printf("nnnn—-send start——n");
 print_eth(SendBuffer,64);
 sendto(sock,&SendBuffer,64,0,(struct sockaddr *)(&dest),sizeof(dest));
 //printf("send to %x:%x:%x:%x:%x:%xn",dest.sll_addr[0],dest.sll_addr[1],dest.sll_addr[2],dest.sll_addr[3],dest.sll_addr[4],dest.sll_addr[5]);
 printf("—send success—-n");

 return 0;
}
 

原文件下载:

tt2 tt1

maze – 回溯法解决迷宫

#include <stdio.h>

struct point {
    int row;
    int col;
};

/* define point stack */
struct point stack[512];

/* define stack pointer */
int top = 0;

/* define push() */
void push(struct point node)
{
    stack[top++] = node;
    return;
}

/* define pop() */
struct point pop(void)
{
    return stack[–top];
}

/* define isempty() */
int isempty(void)
{
    return (top == 0);
}

int maze[5][5] =
{
    { 0, 0, 0, 0, 0 },
    { 1, 1, 1, 1, 0 },
    { 0, 0, 0, 1, 0 },
    { 0, 0, 0, 1, 0 },
    { 0, 0, 0, 1, 0 }
};

struct point father[5][5] =
{
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
};

void print_stack(void)
{
    int i;

    for (i = top-1; i >= 0; i–)
        printf("(%d, %d) n", stack[i].row, stack[i].col);

    printf("————————n");

    return;
}

void print_maze(void)
{
    int i, j;

    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
            printf("%d ", maze[i][j]);
        }
        printf("n");
    }

    printf("————————n");
    return;
}

void print_father(void)
{
    int i, j;
    struct point node;

    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
            node = father[i][j];
            printf("(%2d,%2d) ", node.row, node.col);
        }
        printf("n");
    }

    printf("————————n");
    return;
}

struct point entry = {0, 0};
struct point out = {4, 4};

void backtrack(struct point p)
{
    /* define tmp node = curr point */
    struct point node = p;
    struct point null = {-1, -1};
    struct point top, topfather;
    int row, col;

#ifdef DEBUG
    printf("backtrack is begin n");
    print_stack();
    getchar();
#endif

    /* peak stack top */
    top = pop();
    push(top);

    /* get top father */
    topfather = father[top.row][top.col];

    while(1)
    {
        /* get curr node's row & col */
        row = node.row;
        col = node.col;

        /* clear maze[][] = 0 */
        maze[row][col] = 0;

        /* get current node's father */
        node = father[row][col];

        /* clear father[][] = (-1,-1) */
        father[row][col] = null;
#ifdef DEBUG
        print_maze();
        print_father();
        getchar();
#endif

        /* end condition */
        /* peak stack top point -> topfather */
        /* if node == topfather, break */
        if (node.row == topfather.row && node.col == topfather.col)
            break;
    }

//    printf("backtrack is over n");
}

void print_solution(void)
{
    /* define tmp node = exit point */
    struct point node = out;
    int row, col;
    static int counter = 0;

    while(1)
    {
        /* print curr node */
        printf("(%d, %d) <- ", node.row, node.col);
        row = node.row;
        col = node.col;

        /* get current node's father */
        node = father[row][col];

        /* if current node is (-1,-1), then break */
        if (node.row == -1)
            break;
    }

    printf("n");   
    printf("%d solution is over n", ++counter);   

    return;
}

int main(void)
{
    //struct point entry = {2, 2};
    struct point curr;
    struct point node;
    int flag = 0;

    printf("hello, mazer!n");

    /* init stack, push entry point */
    push(entry);

#ifdef DEBUG
    print_stack();
    print_maze();   
    print_father();   
#endif

    while (!isempty())
    {
        /* get the stack top */
        curr = pop();
       
        /* flag curr point */
        maze[curr.row][curr.col] = 2;

        /* check it */
    //    print_stack();
    //    print_maze();

        /* judgement if curr is exit point */
        if (curr.row == out.row && curr.col == out.col)
        {
            printf("one solution found! n");
            print_solution();

            /* begin to backtrack */
            backtrack(curr);
        //    break;
            continue;
        }

        /* expand from curr */
        flag = 0;

        /* look left */
        if (curr.col-1 >= 0 && maze[curr.row][curr.col-1] == 0)
        {
            /* push left point */
            node.row = curr.row;
            node.col = curr.col – 1;
            /* node 's father is null */
            if (father[node.row][node.col].row == -1)
            {   
                push(node);
                /* remember father */
                father[node.row][node.col] = curr;
                flag++;
            }
        }

        /* look up */
        if (curr.row-1 >= 0 && maze[curr.row-1][curr.col] == 0)
        {
            /* push up point */
            node.row = curr.row – 1;
            node.col = curr.col;
            if (father[node.row][node.col].row == -1)
            {   
                push(node);
                /* remember father */
                father[node.row][node.col] = curr;
                flag++;
            }
        }

        /* look right */
        if (curr.col+1 < 5 && maze[curr.row][curr.col+1] == 0)
        {
            /* push right point */
            node.row = curr.row;
            node.col = curr.col + 1;
            if (father[node.row][node.col].row == -1)
            {   
                push(node);
                /* remember father */
                father[node.row][node.col] = curr;
                flag++;
            }
        }

        /* look down */
        if (curr.row+1 < 5 && maze[curr.row+1][curr.col] == 0)
        {
            /* push down point */
            node.row = curr.row + 1;
            node.col = curr.col;
            if (father[node.row][node.col].row == -1)
            {   
                push(node);
                /* remember father */
                father[node.row][node.col] = curr;
                flag++;
            }
        }
#ifdef DEBUG
        print_stack();
        print_father();
        getchar();
#endif

        /* if no way out (curr node has no expand node) */
        if (flag == 0)
            backtrack(curr);
    }

    printf("maze is over n");
//    print_stack();
   
    return 0;
}
 

bubble – 冒泡排序

#include <stdio.h>

int bubble(int *a,int len)
{
    int i,j;

    for(i=0;i<len-1;i++){
        for(j=0;j<len-i-1;j++){
            if(a[j]>a[j+1]){
                a[j]^=a[j+1];
                a[j+1]^=a[j];
                a[j]^=a[j+1];
            }
        }
    }
    return 0;
}

int main(void)
{
    int a[]={6,5,4,3,2,1},i;

    bubble(a,6);
    for(i=0;i<6;i++){
        printf("%d ",a[i]);

    }
    printf("n");
   
    return 0;
}

 

mergesort – 归并排序

#include <stdio.h>
#define LEN 8
int a[LEN]={5,2,4,7,1,3,2,6};
void merge(int start,int mid,int end)
{
    int n1=mid-start+1;
    int n2=end-mid;
    int left[n1],right[n2];
    int i,j,k;

    for(i=0;i<n1;i++)
        left[i]=a[start+i];
    for(j=0;j<n2;j++)
        right[j]=a[mid+j+1];

    i=j=0;

    for(k=start;i < n1 && j <n2;k++){
        if(left[i]<right[j]){
            a[k]=left[i];
            i++;
        }
        else{
            a[k]=right[j];
            j++;
        }

    }

    if(i<n1){
        for(;i<n1;i++){
            a[k]=left[i];
            k++;
        }
    }
    if(j<n2){
        for(;j<n2;j++){
            a[k]=right[j];
            k++;
        }
    }

}
void sort(int start,int end)
{
    int mid;
    if(start<end){
        mid=(start+end)/2;
        sort(start,mid);
        sort(mid+1,end);
        merge(start,mid,end);

    }

}

int main(void)
{
    int i;
    sort(0,LEN-1);
    for(i=0;i<LEN;i++){
        printf("%d ",a[i]);
    }
    printf("n");

    return 0;
}

 

insertion – 插入排序

void insertion_sort(int *a,int len)
{
    int i,j,key;

    for(i=1;i<len;i++){
        key=a[i];
        j=i-1;
        while(j>=0 && a[j]>key){
            a[j+1]=a[j];
            j–;
        }
        a[j+1]=key;
    }
}

int main(void)
{
    int a[]={12,5,9,3,4,7,4,6,2},i;

    for(i=0;i<9;i++)
        printf("%d ",a[i]);
    printf("n");
    insertion_sort(a,9);
    for(i=0;i<9;i++)
        printf("%d ",a[i]);
    printf("n");
    return 0;
}

 

halfind – 折半查找

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LEN 8

int halfind(int *a,int key)
{
    int start =0,end=LEN-1,mid;
    while(start <= end){
        mid=(start+end)/2;
        if(a[mid] > key){
            end=mid -1;
        }
        else if(a[mid] < key){
            start=mid+1;
        }
        else
            return mid;   

    }

    return -1;
}

int main(int argc,char **argv)
{
    int a[]={1,2,3,4,5,6,7,8};
    printf("%dn",halfind(a,atoi(argv[1])));
   
    return 0;
}

 

==============递归方式===============

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LEN 8
int a[]={1,2,3,4,5,6,7,8};

int halfind(int start,int end,int key)
{
    int mid;
    if(start <= end){

        mid=(start+end)/2;
        if(a[mid] > key){
            halfind(start,mid -1,key);
           
        }
        else if(a[mid] < key){
            halfind(mid+1,end,key);
        }
        else{
            printf("%dn",mid);
            return mid;   
        }

    }

    return -1;
}

int main(int argc,char **argv)
{
    printf("%dn",halfind(0,LEN-1,atoi(argv[1])));
   
    return 0;
}
 

变参 – Variadic 应用

好久没更新博客了,太忙了^-^

这是我写的一个仿scanf函数,比较粗糙,只是练习一下变参

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
void dget(int *b, char k)
{
    char n[20],*a;
    a=n;
    do{
    *a=getchar();
    a++;
    }while(!(*(a-1) == 'n' || *(a-1) == k));
    *(a-1)='';
    *b=atoi(n);
}

void sget(char *a,char k)
{
    do{
    *a=getchar();
    a++;
    }while(!(*(a-1) == 'n' || *(a-1) == k));
    *(a-1)='';
}

void cget(char *a)
{
    *a=getchar();
    getchar();
}

int myscanf(char *list, …)
{
    va_list ap;
    char *p;
    int *num;
   

    va_start(ap,list);
    for(;*list!='';list++){
       
        if(*list=='%'){
            switch(*(list+1)){
                case 'c':
                    p=(char *)va_arg(ap,int);
                    cget(p);
                    list++;
                    continue;
                case 's':
                    p=(char *)va_arg(ap,int);
                    sget(p,*(list+2));
                    list++;
                    continue;
                case 'd':
                    num=(int *)va_arg(ap,int);
                    dget(num,*(list+2));
                    list++;
                    continue;
                default:
                    //list++;
                    break;
            }
        }
    }

    return 0;
}

int main(void)
{
    int a,c;
    char b[30];
    myscanf("%s,%d,%c",b,&c,&a);
    printf("%s,%c,%d",b,a,c);
    return 0;
}
 

IP 分片与重组

IP:分片与重组

1. 引言
为了与互联网上的任意计算机通信,每个应用TCP/IP的计算机必须具有分片和重组的代码,一个设计良好的应用软件,会生成足够小的数据报,
因此主机并不需要经常执行分片任务.

2. 数据报的分片
分片发生在选择路由之后,以及放入接口队列之前.IP把数据报长度与MTU进行比较,确定是否需要分片.
如需分片,IP首先生成多个数据报,并将每个数据报中的分片位置1,将源数据报中的数据按顺序分片,并将它们装入这些数据报中.
它还在同一源数据报产生的所有数据报片中将MF位置为1,末尾片除外.IP一边分片,一边将它们传递给网络接口发送出去.

2.1 为一个数据报片再次分片
对于MF未置1的片,和上边说的没区别,除了最后一个片外,其它全置1.但对于MF为1的源片,再次分片后的所有分片MF全置1

3. 分片的实现

/* ipputp.c – ipputp */

#include <conf.h>
#include <kernel.h>
#include <network.h>

/*————————————————————————
 * ipputp  –  发送一个数据包到一个接口的输出队列
 *————————————————————————
 */
int
ipputp(unsigned ifn, IPaddr nh, struct ep *pep)
{
    struct    netif    *pni = &nif[ifn];        /* 接口指针*/
    struct    ip    *pip;                /* IP报指针*/
    int        hlen, maxdlen, tosend, offset, offindg;

    if (pni->ni_state == NIS_DOWN) {            /* 接口关闭则返回*/
        freebuf(pep);
        return SYSERR;
    }
    pip = (struct ip *)pep->ep_data;            /* IP报指向*/
    if (pip->ip_len <= pni->ni_mtu) {        /* IP报长度小于等于接口MTU,则直接发送数据报*/
        pep->ep_nexthop = nh;
        pip->ip_cksum = 0;
        iph2net(pip);
        pep->ep_order &= ~EPO_IP;
        pip->ip_cksum = cksum((WORD *)pip, IP_HLEN(pip));
        return netwrite(pni, pep, EP_HLEN+net2hs(pip->ip_len));
    }
    /* 否则,我们必须分片 */

    if (pip->ip_fragoff & IP_DF) {            /* 能否分片,不能分片则报错并返回*/
        IpFragFails++;
        icmp(ICT_DESTUR, ICC_FNADF, pip->ip_src, pep, 0);
        return OK;
    }
    maxdlen = (pni->ni_mtu – IP_HLEN(pip)) &~ 7;    /* 最大长度为MTU减去IP头长度,并增加到8的倍数*/
    offset = 0;                    /* 偏移量*/
    offindg = (pip->ip_fragoff & IP_FRAGOFF)<<3;    /* 偏移量,保存控制位*/
    tosend = pip->ip_len – IP_HLEN(pip);        /* 要发送的IP报长度,不包括IP报头*/

    while (tosend > maxdlen) {            /* 仅当剩余的数据大于可发送的最大数据量时才发送*/
        if (ipfsend(pni,nh,pep,offset,maxdlen,offindg) != OK) {    /* 生成并发送分片*/
            IpOutDiscards++;
            freebuf(pep);
            return SYSERR;
        }
        IpFragCreates++;
        tosend -= maxdlen;
        offset += maxdlen;
        offindg += maxdlen;            /* */
    }
    IpFragOKs++;
    IpFragCreates++;
    hlen = ipfhcopy(pep, pep, offindg);        /* 首部拷贝处理,返回首部长度*/
    pip = (struct ip *)pep->ep_data;            /* 取IP数据报*/
    /*处理最后一个分片,当最后剩余的数据小于等于可发送的最大数据量 */
    memcpy(&pep->ep_data[hlen], &pep->ep_data[IP_HLEN(pip)+offset],
        tosend);                    /* 修改源报,使之变为最后一个报片*/
    /*非末尾的数据报片再次分片时,保证MF全为1 */
    pip->ip_fragoff = (pip->ip_fragoff & IP_MF)|(offindg>>3);
    pip->ip_len = tosend + hlen;
    pip->ip_cksum = 0;
    iph2net(pip);
    pep->ep_order &= ~EPO_IP;
    pip->ip_cksum = cksum((WORD *)pip, hlen);
    pep->ep_nexthop = nh;
    return netwrite(pni, pep, EP_HLEN+net2hs(pip->ip_len));
}

3.1 发送一个数据报片

/* ipfsend.c – ipfsend */

#include <conf.h>
#include <kernel.h>
#include <network.h>

int ipfhcopy(struct ep *, struct ep *, unsigned);

/*————————————————————————
 *  ipfsend –  发送一个IP数据报的分片
 *————————————————————————
 */
int
ipfsend(struct netif *pni, IPaddr nexthop, struct ep *pep,
    unsigned offset, unsigned maxdlen, unsigned offindg)
{
    struct    ep    *pepnew;
    struct    ip    *pip, *pipnew;
    int        hlen, len;

    pepnew = (struct ep *)getbuf(Net.netpool);        /* 申请一个新帧的缓冲区*/
    if (pepnew == (struct ep *)SYSERR)
        return SYSERR;
    pepnew->ep_order = ~0;
    hlen = ipfhcopy(pepnew, pep, offindg);    /* 复制头 */

    pip = (struct ip *)pep->ep_data;        /* 源IP报的指向*/
    pipnew = (struct ip *)pepnew->ep_data;    /* 新生成的IP报*/
    pipnew->ip_fragoff = IP_MF | (offindg>>3);
    pipnew->ip_len = len = maxdlen + hlen;
    pipnew->ip_cksum = 0;

    iph2net(pipnew);
    pepnew->ep_order &= ~EPO_IP;        /* 清除字节顺序*/
    pipnew->ip_cksum = cksum((WORD *)pipnew, hlen);

    memcpy(&pepnew->ep_data[hlen],        /* 复制数据*/
        &pep->ep_data[IP_HLEN(pip)+offset], maxdlen);
    pepnew->ep_nexthop = nexthop;

    return netwrite(pni, pepnew, EP_HLEN+len);    /* 发送并返回 */
}

3.2 复制数据报首部

/* ipfhcopy.c – ipfhcopy */

#include <conf.h>
#include <kernel.h>
#include <network.h>

/*————————————————————————
 *  ipfhcopy –  copy the hardware, IP header, and options for a fragment
 *————————————————————————
 */
int
ipfhcopy(struct ep *pepto, struct ep *pepfrom, unsigned offindg)
{
    struct    ip    *pipfrom = (struct ip *)pepfrom->ep_data;    /* 旧IP报*/
    unsigned    i, maxhlen, olen, otype;
    unsigned    hlen = (IP_MINHLEN<<2);        /* IP头最小长度*4 ,就是以字节为单位了*/

    if (offindg == 0) {    /* 偏移为0,说明是第一个分片,复制帧的头和IP头到新的帧*/
        memcpy(pepto, pepfrom, EP_HLEN+IP_HLEN(pipfrom));
        return IP_HLEN(pipfrom);
    }
    /* 以下就说明不是第一个IP分片了*/
    memcpy(pepto, pepfrom, EP_HLEN+hlen);        /* 复制帧的头和除了IP选项外的报头*/

    /*复制选项 */

    maxhlen = IP_HLEN(pipfrom);        /* 包括选项的IP头的长度*/
    i = hlen;                /* 不包括选项的IP头长度*/
    while (i < maxhlen) {            /* 最小头比最大头小,说明有IP选项*/
        otype = pepfrom->ep_data[i];    /* IP选项*/
        olen = pepfrom->ep_data[++i];    /* 选项长度*/
        if (otype & IPO_COPY) {        /* 如果复制位为1*/
            memcpy(&pepto->ep_data[hlen],
                &pepfrom->ep_data[i-1], olen);        /* 复制这个选项到所有新的帧*/
            hlen += olen;
        } else if (otype == IPO_NOP || otype == IPO_EOOP) {    /* 选项结束或没有操作*/
            pepto->ep_data[hlen++] = otype;
            olen = 1;
        }
        i += olen-1;
        
        if (otype == IPO_EOOP)
            break;
    }
    /* pad to a multiple of 4 octets */
    while (hlen % 4)            /* 填充到4字节的整数倍*/
        pepto->ep_data[hlen++] = IPO_NOP;
    return hlen;
}

4. 数据报的重组

4.1 数据结构

/* ipreass.h */

/* Internet Protocol (IP)  reassembly support */

#define IP_FQSIZE    10    /* 分片队列的数大数量 */
#define IP_MAXNF    10    /* 分片/数据报 的最大数量 */
#define    IP_FTTL        60    /* 生存时间(秒)*/

/* ipf_state flags */

#define    IPFF_VALID    1    /* 内容是有效的 */
#define    IPFF_BOGUS    2    /* 丢弃        */
#define    IPFF_FREE    3    /* 这个队列可以自由分配    */

struct    ipfq    {
    char    ipf_state;        /* 队列状态,值为上边 3种        */
    IPaddr    ipf_src;        /* 源IP地址 */
    short    ipf_id;            /* 数据报ID */
    int    ipf_ttl;        /* 数据报重组的生存时间 */
    int    ipf_q;            /* 分片存储的链表 */
};

extern    int    ipfmutex;        /* 互斥 mutex for ipfqt[] */
extern    struct    ipfq    ipfqt[];    /* IP分片队列表        */

int ipfsend(struct netif *, IPaddr, struct ep *, unsigned, unsigned,
    unsigned);
int ipfhcopy(struct ep *, struct ep *, unsigned);

4.2 互斥操作

为了何证进程在数据报片的链表时不会互相干扰,重组程序代码使用了一个互斥信号量ipfmutex.在ipreass.h中

4.3 在链表中加入一个数据报片

/* ipreass.c – ipreass */

#include <conf.h>
#include <kernel.h>
#include <network.h>

int ipfadd(struct ipfq *, struct ep *);
struct    ep    *ipfjoin(struct ipfq *);

/*————————————————————————
 *  ipreass  –  reassemble an IP datagram, if necessary
 *    returns packet, if complete; 0 otherwise
 *  IP数据报重组,如果报片到齐则重组该包,并返回完整的数据报,否则返回0
 *————————————————————————
 */
struct ep *
ipreass(struct ep *pep)
{
    struct    ep    *pep2;
    struct    ip    *pip;
    int        firstfree;
    int        i;

    pip = (struct ip *)pep->ep_data;        /* 得到IP数据报的*/

    wait(ipfmutex);                /* 互斥*/

    if ((pip->ip_fragoff & (IP_FRAGOFF|IP_MF)) == 0) {    /*如果不是分片,返回当前帧*/
        signal(ipfmutex);
        return pep;
    }
    IpReasmReqds++;
    firstfree = -1;
    /* 以下情况为是分片 */
    for (i=0; i<IP_FQSIZE; ++i) {
        struct    ipfq    *piq = &ipfqt[i];

        if (piq->ipf_state == IPFF_FREE) {        /* 队列未使用,则继续*/
            if (firstfree == -1)
                firstfree = i;
            continue;
        }
        if (piq->ipf_id != pip->ip_id)            /* 队列ID不等于分片ID,则继续*/
            continue;
        if (piq->ipf_src != pip->ip_src)            /* 源地址不同,则继续*/
            continue;
        /* 找到匹配 */
        if (ipfadd(piq, pep) == 0) {            /* 把该分片加入匹配的队列*/
            signal(ipfmutex);
            return 0;
        }
        pep2 = ipfjoin(piq);                /* 检查是否可以重组数据报*/
        signal(ipfmutex);
        return pep2;
        
    }
    /* 没有匹配 */

    if (firstfree < 0) {                    /* 检查是否有空闲队列*/
        /* no room– drop */                /* 没有空闲则丢弃*/
        freebuf(pep);
        signal(ipfmutex);
        return 0;
    }
    ipfqt[firstfree].ipf_q = newq(IP_FQSIZE, QF_WAIT);    /* 分配一个空闲表项*/
    if (ipfqt[firstfree].ipf_q < 0) {
        freebuf(pep);
        signal(ipfmutex);
        return 0;
    }
    ipfqt[firstfree].ipf_src = pip->ip_src;            /* 填充*/
    ipfqt[firstfree].ipf_id = pip->ip_id;
    ipfqt[firstfree].ipf_ttl = IP_FTTL;
    ipfqt[firstfree].ipf_state = IPFF_VALID;
    ipfadd(&ipfqt[firstfree], pep);
    signal(ipfmutex);
    return 0;
}

int    ipfmutex;
struct    ipfq    ipfqt[IP_FQSIZE];

4.4 溢出时的丢弃

/* ipfadd.c – ipfadd */

#include <conf.h>
#include <kernel.h>
#include <proc.h>
#include <network.h>

/*————————————————————————
 *  ipfadd  –  增加一个分片到一个IP碎片队列
 *————————————————————————
 */
Bool
ipfadd(struct ipfq *iq, struct ep *pep)
{
    struct    ip    *pip;
    int        fragoff;

    if (iq->ipf_state != IPFF_VALID) {            /* 分片队列无效,则丢弃*/
        freebuf(pep);
        return FALSE;
    }
    pip = (struct ip *)pep->ep_data;                /* 得到IP数据报的*/
    fragoff = pip->ip_fragoff & IP_FRAGOFF;            /* 得到偏移量*/
    /* -fragoff用作关键值,越大越靠前 */
    if (enq(iq->ipf_q, pep, -fragoff) < 0) {            /* 举出丢弃并释放内存*/
        /* overflow– free all frags and drop */
        freebuf(pep);
        IpReasmFails++;
        while (pep = (struct ep *)deq(iq->ipf_q)) {    /* 从队列删除帧并释放帧*/
            freebuf(pep);
            IpReasmFails++;
        }
        freeq(iq->ipf_q);                /* 释放队列*/
        iq->ipf_state = IPFF_BOGUS;
        return FALSE;
    }
    iq->ipf_ttl = IP_FTTL;        /* 重置生存时间 */
    return TRUE;
}

4.5 测试一个完整的数据据报

/* ipfjoin.c – ipfjoin */

#include <conf.h>
#include <kernel.h>
#include <proc.h>
#include <network.h>

struct    ep    *ipfcons(struct ipfq *);

/*————————————————————————
 *  ipfjoin  –  join fragments, if all collected
 *————————————————————————
 */
struct ep *
ipfjoin(struct ipfq *iq)
{
    struct    ep    *pep;
    struct    ip     *pip = 0;
    int        off, packoff;

    if (iq->ipf_state == IPFF_BOGUS)
        return 0;
    /* see if we have the whole datagram */
    /* 看我们是否有整个的数据包 */

    off = 0;
    while (pep=(struct ep *)seeq(iq->ipf_q)) {        /* 取出帧*/
        pip = (struct ip *)pep->ep_data;            /* 取出IP报*/
        packoff =  (pip->ip_fragoff & IP_FRAGOFF)<<3;
        if (off < packoff) {                /* 偏移大于0*/
            while(seeq(iq->ipf_q))            /* 一个不满足,说没没全到*/
                /*empty*/;
            return 0;
        }
        off = packoff + pip->ip_len – IP_HLEN(pip);    /*计算总长度,不含头*/
    }
    /* 这里利用off来测试,首先ipfjoin查看当前数据报片的偏移量是否与off值相符。
       如果当前数据报片的偏移量超过了off的值,那么必定有尚未到达的数据报片,
       因此ipfjoin返回0。如果偏移量与off值一致,那么ipfjoin通过将off值加上当前
       数据报片长度减去首部计算出下一个数据报片的偏移量。*/
    if (off > MAXLRGBUF) {        /* 超过缓冲区则丢弃 – too big for us to handle */
        while (pep = (struct ep *)deq(iq->ipf_q))
            freebuf(pep);
        freeq(iq->ipf_q);
        iq->ipf_state = IPFF_FREE;
        return 0;
    }
    if (pip == 0 || (pip->ip_fragoff & IP_MF) == 0)        /* 没有IP报或没有更多的分片*/
        return ipfcons(iq);                /* 收集数据报片并重建完整的数据报 */

    return 0;
}

4.6 将数据报片组装成完整的数据报

/* ipfcons.c – ipfcons */

#include <conf.h>
#include <kernel.h>
#include <network.h>

/*————————————————————————
 *  ipfcons  –  从IP碎片队列构建一个分组
 *————————————————————————
 */
struct ep *
ipfcons(struct ipfq *iq)
{
    struct    ep    *pep, *peptmp;
    struct    ip    *pip;
    int        off, seq;

    pep = (struct ep *)getbuf(Net.lrgpool);            /* 申请缓存空间*/
    if (pep == (struct ep *)SYSERR) {            /* 申请失败则丢弃该报*/
        while (peptmp = (struct ep *)deq(iq->ipf_q)) {
            IpReasmFails++;
            freebuf(peptmp);
        }
        freeq(iq->ipf_q);                /* 释放队列*/
        iq->ipf_state = IPFF_FREE;
        return 0;
    }
    /*  复制帧和IP报头 */

    peptmp = (struct ep *)deq(iq->ipf_q);            /* 取出一个分片*/
    pip = (struct ip *)peptmp->ep_data;            /* 得到IP报*/
    off = IP_HLEN(pip);                    /* 得到IP头长度*/
    seq = 0;
    memcpy(pep, peptmp, EP_HLEN+off);            /* 复制IP报头到pep*/

    /* 复制数据部分 */
    while (peptmp != 0) {
        int dlen, doff;

        pip = (struct ip *)peptmp->ep_data;        /* 取IP报*/
        doff = IP_HLEN(pip) + seq
            – ((pip->ip_fragoff&IP_FRAGOFF)<<3);
        dlen = pip->ip_len – doff;
        memcpy(pep->ep_data+off, peptmp->ep_data+doff, dlen);
        off += dlen;
        seq += dlen;
        freebuf(peptmp);
        peptmp = (struct ep *)deq(iq->ipf_q);
    }

    /* 修复分组的头 */
    pip = (struct ip *)pep->ep_data;                /* 取出IP报*/
    pip->ip_len = off;                    /* 修复长度*/
    pip->ip_fragoff = 0;                    /* 修复偏移量*/

    /* 释放资源 */
    freeq(iq->ipf_q);
    iq->ipf_state = IPFF_FREE;
    IpReasmOKs++;
    return pep;
}

5. 数据报片链表的维护管理

/* ipftimer.c – ipftimer */

#include <conf.h>
#include <kernel.h>
#include <network.h>

/*————————————————————————
 * ipftimer – 更新生存周期并删除过期的碎片
 *————————————————————————
 */
void
ipftimer(int gran)
{
    struct    ep    *pep;
    struct    ip    *pip;
    int        i;

    wait(ipfmutex);                        /* 申请互斥量 */
    for (i=0; i<IP_FQSIZE; ++i) {                /* 遍历队列*/
        struct ipfq *iq = &ipfqt[i];

        if (iq->ipf_state == IPFF_FREE)            /* 空闲则继续*/
            continue;
        iq->ipf_ttl -= gran;                /* 非空闲则ttl-1*/
        if (iq->ipf_ttl <= 0) {                /* 生存周期到达则*/
            if (iq->ipf_state == IPFF_BOGUS) {    /* 如果为丢弃状态,则继续*/
                /* resources already gone */
                iq->ipf_state = IPFF_FREE;
                continue;
            }
            if (pep = (struct ep *)deq(iq->ipf_q)) {    /* 取分片*/
                IpReasmFails++;
                pip = (struct ip *)pep->ep_data;    /* 取IP报*/
                icmp(ICT_TIMEX, ICC_FTIMEX,    /* 向源站报错*/
                    pip->ip_src, pep, 0);
            }
            while (pep = (struct ep *)deq(iq->ipf_q)) {    /* 释放资源*/
                IpReasmFails++;
                freebuf(pep);
            }
            freeq(iq->ipf_q);            /* 释放队列*/
            iq->ipf_state = IPFF_FREE;
        }
    }
    signal(ipfmutex);                    /* 互斥解锁*/
}

6. 初始化

/* ipfinit.c – ipfinit */

#include <conf.h>
#include <kernel.h>
#include <network.h>

/*————————————————————————
 * ipfinit  –  initialize IP fragment queue data structures
 *————————————————————————
 */
void
ipfinit(void)
{
    int    i;

    ipfmutex = screate(1);            /* 不多说了,简单,太~~~,这个看不明白就不用看了. 🙂 */
    for (i=0; i<IP_FQSIZE; ++i)
        ipfqt[i].ipf_state = IPFF_FREE;
}
 

IP 选路表 和 选路算法

1 引言
讨论选择路由的细节,选路表的结构,以及实现算法,路由如何使用子网掩码,如何区分网络路由子网路由以及主机路由

2 路由维护和查找
应当选择能使查找路由花费最小的IP数据结构和算法,维护路由的花费则并不那么重要
利用桶散列(bucket hashing)迅速找到正确的散列表元

3 选路表结构
保存路由的主要数据结构是数组。数组的每个元素对应一个散列表元,并包含一个指针,指向被装入这个散列表元中的通主目的站的路由记录链表。表中每个记录包含一个IP目的地址,子网掩码,下一跳地址,用于向下一跳地址发送数据的网络接口,以及其他的路由管理中使用的信息。由于IP预先并不知道子网掩码,它公使用IP目的地址的网络部分计算散列函数,在一个链表中查找表项时,使用的是完整的目的地址来进行比较。

4 选路表数据结构

/* route.h – RTFREE */

/* 路由表项 */
struct route {
IPaddr rt_net; /* 路由的目的地址 */
IPaddr rt_mask; /* 路由的掩码 */
IPaddr rt_gw; /* 下一跳的IP */
u_short rt_metric; /* 距离度量 */
u_short rt_ifnum; /* 接口的序号 */
short rt_key; /* 排序关键字 */
short rt_ttl; /* 生存时间(秒) */
struct route *rt_next; /* 哈希值指向下一个条目 */
/* stats */
int rt_refcnt; /* 引用计数 */
int rt_usecnt; /* 记录该路由使用的次数 */
};

/* 路由表的全局数据 */
struct rtinfo {
struct route *ri_default; /* 包含默认路由的下一跳地址 */
int ri_bpool; /* 结点的地址??? Route.ri_bpool = mkpool(sizeof(struct route), RT_BPSIZE) 现在还不太明白 */
Bool ri_valid; /* 此路由的数据结构是否被初始化 */
int ri_mutex; /* 互斥信号 */
};

#define RT_DEFAULT ip_anyaddr /* 默认的网络地址 全0 */
#define RT_LOOPBACK ip_loopback /* 回环地址 */
#define RT_TSIZE 512 /* 散列表长度??-these are pointers; it’s cheap */
#define RT_INF 999 /* 路由永不超时 */

#define RTM_INF 16 /* 一个最大距离度量 – an infinite metric */

/* rtget()的第二个参数… */

#define RTF_REMOTE 0 /* 远程主机产生的通信 */
#define RTF_LOCAL 1 /* 本地产生的通信 */

#define RT_BPSIZE 100 /* 路由的最大数量 */

/* RTFREE – 删除一个路由引用(假定持有ri_mutex) */

#define RTFREE(prt)
if (–prt->rt_refcnt <= 0) { freebuf(prt); } extern struct rtinfo Route; extern struct route *rttable[]; int rtadd(IPaddr, IPaddr, IPaddr, unsigned, unsigned, unsigned); int rtdel(IPaddr, IPaddr), rthash(IPaddr), rtfree(struct route *); struct route *rtget(IPaddr, Bool); void rtinit(void); void ipredirect(struct ep *, unsigned, struct route *); void ipdbc(unsigned, struct ep *, struct route *); 5 路由的生成源及保持时间 选路表项的易失性与它的来源有关(从备份存储器中得到,ICMP或选路协议,网络管理员手动操作),但为了排除网络中的路由问题,管理员可以推翻任何路由并建立不可改变的永久的路由 6 为数据报选择路由 6.1 实用过程 /* netnum.c - netnum */ #include
#include
#include

/*————————————————————————
* netnum – 计算一个给定IP 地址的网络部分
*————————————————————————
*/
IPaddr
netnum(IPaddr ipa)
{
IPaddr mask = ~0;

if (IP_CLASSA(ipa)) mask = hl2net(0xff000000);
if (IP_CLASSB(ipa)) mask = hl2net(0xffff0000);
if (IP_CLASSC(ipa)) mask = hl2net(0xffffff00);
return ipa & mask; /* 返回一个主机地址字节为全0的地址*/
}

/* netmatch.c – netmatch */

#include
#include
#include

/*————————————————————————
* netmatch – 是否是这个网络上的地址?
*————————————————————————
*/
Bool
netmatch(IPaddr dst, IPaddr net, IPaddr mask, Bool islocal)
{
if ((dst & mask) != (net & mask)) /* 目的地址与选路表中地址比较*/
return FALSE;
/*
* 源地址为本地可以只匹配单播地址 (主机为路由)
*/
if (islocal) /* 如果是本地*/
if (isbrc(dst) || IP_CLASSD(dst)) /* 如果目的地址不是广播地址,或不是D类*/
return mask != ip_maskall; /* 并且掩码不为全1,则返回真,否则为假*/
return TRUE;
}

/* netmask.c – netmask */

#include
#include
#include

IPaddr netnum(IPaddr);

/*————————————————————————
* netmask – 为给定网络设定默认掩码
*————————————————————————
*/
IPaddr
netmask(IPaddr net)
{
IPaddr netpart;
int i;

if (net == 0) /* 目的地址为全0,则使用默认路由,返回全0掩码*/
return net;
/* 网络匹配检查 (子网) */

netpart = netnum(net); /* 提取出网络部分*/
for (i=0; i
#include
#include

/*————————————————————————
* rthash – 计算网络的哈希值
*————————————————————————
*/
int
rthash(IPaddr net)
{
int bc = IP_ALEN; /* # 字节数 */
unsigned int hv = 0; /* 哈希值 */

if (IP_CLASSA(net)) bc = 1;
else if (IP_CLASSB(net)) bc = 2;
else if (IP_CLASSC(net)) bc = 3;
else if (IP_CLASSD(net))
return ((net>>24) & 0xf0) % RT_TSIZE; /* D类前4比特乘16再与散列表长度取余数*/
while (bc–)
hv += ((char *)&net)[bc] & 0xff; /* 每8位相加*/
return hv % RT_TSIZE; /* 返回除以散列长度后的余数*/
}

6.2 获得一个路由

/* rtget.c – rtget */

#include
#include
#include

/*————————————————————————
* rtget – 获得一个给定的IP地址的路由
*————————————————————————
*/
struct route *
rtget(IPaddr dest, Bool local)
{
struct route *prt;
int hv;

if (!Route.ri_valid) /* 如果路由的数据结构没被初始化则应该先初始化*/
rtinit();
wait(Route.ri_mutex); /* 等待信号互斥量*/
hv = rthash(dest); /* 计算哈希值*/
for (prt=rttable[hv]; prt; prt=prt->rt_next) {
if (prt->rt_ttl <= 0) continue; /* 路由过期 */ if (netmatch(dest, prt->rt_net, prt->rt_mask, local)) /* 如果网络地址匹配*/
if (prt->rt_metric < RTM_INF) /* 并且距离量度小于最大的量度*/ break; /* 则退出for循环*/ } if (prt == 0) /* 如果没有找到匹配的网络地址*/ prt = Route.ri_default; /* 使用默认路由 */ if (prt != 0 && prt->rt_metric >= RTM_INF) /*如果找到匹配且路离量度大于最大的量度*/
prt = 0; /* prt指向0*/
if (prt) {
prt->rt_refcnt++; /* 引用计数加1*/
prt->rt_usecnt++; /* 统计计数加1*/
}
signal(Route.ri_mutex); /* 释放互斥量*/
return prt;
}

6.3 数据结构初始化

/* rtinit.c – rtinit */

#include
#include
#include
#include

struct rtinfo Route;
struct route *rttable[RT_TSIZE];

/*————————————————————————
* rtinit – 初始化路由表
*————————————————————————
*/
void
rtinit(void)
{
int i;

for (i=0; i
#include
#include #include

extern Bool dorip; /* TRUE 如果我们正在运行的RIP输出 */
extern int rippid; /* 输出的RIP的pid,如果运行 */

/*————————————————————————
* rttimer – 更新TTLS及删除过期路由
*————————————————————————
*/
void
rttimer(unsigned int delta)
{
struct route *prt, *prev;
Bool ripnotify;
int i;

if (!Route.ri_valid) /* 路由未被初始化则返回*/
return;
wait(Route.ri_mutex); /* 等待互斥量*/

ripnotify = FALSE; /* RIP通知关闭*/
for (i=0; irt_ttl != RT_INF) /* 如果生存时间不等于永久*/
prt->rt_ttl -= delta; /* 生存时间减去相应的时间*/
if (prt->rt_ttl <= 0) { /* 如果生存时间小于等于0*/ #ifdef RIP /* 条件编译,当打开RIP时*/ if (dorip && prt->rt_metric < RTM_INF) { /*RIP打开且距离小于最大距离*/ prt->rt_metric = RTM_INF; /* 设置距离为最大距离*/
prt->rt_ttl = RIPZTIME; /* 生存时间为无穷*/
ripnotify = TRUE; /* 打开RIP通知*/
continue;
}
#endif /* RIP */
if (prev) { /*如果prev不为空,删除prt指向的表项*/
prev->rt_next = prt->rt_next;
RTFREE(prt);
prt = prev->rt_next;
} else { /*否则说明prt就是第一个表项*/
rttable[i] = prt->rt_next; /*删除第一个表项*/
RTFREE(prt);
prt = rttable[i];
}
continue;
}
prev = prt; /* 指向下一个*/
prt = prt->rt_next; /* 指向下一个*/
}
}
prt = Route.ri_default; /* 使用默认路由*/
if (prt && (prt->rt_ttlrt_ttl -= delta) <= 0) { /* 默认路由不合适*/ #ifdef RIP if (dorip && prt->rt_metric < RTM_INF) { /* RIP打开且距离小于最大距离 */ prt->rt_metric = RTM_INF; /* 距离为最大距离量度 */
prt->rt_ttl = RIPZTIME; /* 生存时间为无穷*/
} else
#endif /* RIP */
{
RTFREE(Route.ri_default); /* 释放默认路由 */
Route.ri_default = 0; /* 清除默认路由指针*/
}
}
signal(Route.ri_mutex); /* 释放互斥量*/
#ifdef RIP
if (dorip && ripnotify) /* RIP打开并且RIP通知打开*/
send(rippid, 0); /* 发送任何东西,但超时 */
#endif /* RIP */
return;
}

7.1 增加路由

/* rtadd.c – rtadd */

#include
#include
#include #include

struct route *rtnew(IPaddr, IPaddr, IPaddr, unsigned,unsigned,unsigned);
void rtinit(void);
int rthash(IPaddr);

/*————————————————————————
* rtadd – 添加一个路由到路由表
*————————————————————————
*/
int
rtadd(IPaddr net, IPaddr mask, IPaddr gw, unsigned metric,
unsigned intf, unsigned ttl)
{
struct route *prt, *srt, *prev;
Bool isdup;
int hv, i;

if (!Route.ri_valid) /* 初始化*/
rtinit();

prt = rtnew(net, mask, gw, metric, intf, ttl); /* 建立新的结点*/
if (prt == (struct route *)SYSERR) /* 分配失败则返回错误*/
return SYSERR;

/* 计算,路由在队列中的键 */
prt->rt_key = 0;
for (i=0; i<32; ++i) prt->rt_key += (mask >> i) & 1;
wait(Route.ri_mutex); /* 等待互斥量*/

/* 默认路由的特殊情况 */
if (net == RT_DEFAULT) { /* 如果网络地址为任意,全0*/
if (Route.ri_default) /* 默认路由不为空*/
RTFREE(Route.ri_default); /* 释放默认路由*/
Route.ri_default = prt; /* 用新的路由代替*/
signal(Route.ri_mutex); /* 释放互斥量*/
return OK;
}
prev = NULL;
hv = rthash(net); /* 计算哈希值*/
isdup = FALSE; /* 是否有相同地址的路由表项*/
/* 查找是否有相同的路由*/
for (srt=rttable[hv]; srt; srt = srt->rt_next) { /*srt 为空则退出for*/
if (prt->rt_key > srt->rt_key) /* */
break;
if (srt->rt_net == prt->rt_net && /* 网络地址和掩码均相同,找到相同的地址的路由*/
srt->rt_mask == prt->rt_mask) {
isdup = TRUE; /* isdup为真*/
break;
}
prev = srt;
}
if (isdup) { /* isdup为真,说明有相同的路由表项*/
struct route *tmprt;

if (srt->rt_gw == prt->rt_gw) { /* 源路由表与新路由表的下一跳相同 */
/* 更新新由表 */
#ifdef RIP /* RIP打开的情况,上边说过很多回了,下边不再多说*/
if (dorip) {
srt->rt_ttl = ttl;
if (srt->rt_metric != metric) {
if (metric == RTM_INF)
srt->rt_ttl = RIPZTIME;
send(rippid, 0);
}
}
#endif /* RIP */
srt->rt_metric = metric; /* 更新距离量度*/
RTFREE(prt); /* 释放prt*/
signal(Route.ri_mutex); /* 释放互斥量*/
return OK;
}
/* else, someone else has a route there… */
if (srt->rt_metric <= prt->rt_metric) { /* 源路由比新路由具有更小的距离并且下一跳地址不同*/
/* 没有更好的路由线路,放弃新的路由 */

RTFREE(prt);
signal(Route.ri_mutex); /* 释放互斥量*/
return OK;
}
#ifdef RIP
else if (dorip)
send(rippid, 0);
#endif /* RIP */
tmprt = srt; /* 执行到这里说明新路由更优,释放旧的路由*/
srt = srt->rt_next;
RTFREE(tmprt);
}
#ifdef RIP
else if (dorip)
send(rippid, 0);
#endif /* RIP */
prt->rt_next = srt; /* 插入新的路由*/
if (prev) /* 插入到链表的中间*/
prev->rt_next = prt;
else /* 插入到链表的开始*/
rttable[hv] = prt;
signal(Route.ri_mutex);
return OK;
}

建立新的结点,很简单不多说了

/* rtnew.c – rtnew */

#include
#include
#include

/*————————————————————————
* rtnew – 创建一个路由结构
*————————————————————————
*/
struct route *
rtnew(IPaddr net, IPaddr mask, IPaddr gw, unsigned metric,
unsigned ifnum, unsigned ttl)
{
struct route *prt;

prt = (struct route *)getbuf(Route.ri_bpool);
if (prt == (struct route *)SYSERR) {
IpRoutingDiscards++;
return (struct route *)SYSERR;
}

prt->rt_net = net;
prt->rt_mask = mask;
prt->rt_gw = gw;
prt->rt_metric = metric;
prt->rt_ifnum = ifnum;
prt->rt_ttl = ttl;
prt->rt_refcnt = 1; /* our caller */
prt->rt_usecnt = 0;
prt->rt_next = NULL;
return prt;
}

7.2 删除路由

/* rtdel.c – rtdel */

#include
#include
#include

/*————————————————————————
* rtdel – 删除给定网络的路由和掩码
*————————————————————————
*/
int
rtdel(IPaddr net, IPaddr mask)
{
struct route *prt, *prev;
int hv, i;

if (!Route.ri_valid) /* 未被初始化则返回出错*/
return SYSERR;
wait(Route.ri_mutex); /* 等待互斥量*/
if (Route.ri_default && /* 默认路由存在并且net参数与之相同,则删除默认路由*/
net == Route.ri_default->rt_net) {
RTFREE(Route.ri_default);
Route.ri_default = 0;
signal(Route.ri_mutex);
return OK;
}
hv = rthash(net); /* 计算哈希值*/

prev = NULL;
/* 查找匹配的路由*/
for (prt = rttable[hv]; prt; prt = prt->rt_next) {
if (net == prt->rt_net &&
mask == prt->rt_mask)
break;
prev = prt;
}
if (prt == NULL) { /* 没有找到匹配的路由*/
signal(Route.ri_mutex);
return SYSERR;
}
if (prev) /* prev不为空,说明匹配的路由在链表中间,并删除结点*/
prev->rt_next = prt->rt_next;
else /* 路由在链表开头*/
rttable[hv] = prt->rt_next;
RTFREE(prt); /* 释放结点*/
signal(Route.ri_mutex); /* 释放互斥量*/
return OK;
}

释放结点用的,没什么可说的,就是使用互斥量,调用一个宏
/* rtfree.c – rtfree */

#include
#include
#include

/*————————————————————————
* rtfree – remove one reference to a route
*————————————————————————
*/
int
rtfree(struct route *prt)
{
if (!Route.ri_valid)
return SYSERR;
wait(Route.ri_mutex);
RTFREE(prt);
signal(Route.ri_mutex);
return OK;
}

8. IP选项处理
没做什么工做,只是分析了一下IP首部中选面长度八位组的信息
/* ipdoopts.c – ipdoopts */

#include
#include
#include

/*————————————————————————
* ipdoopts – do gateway handling of IP options
*————————————————————————
*/
int
ipdoopts(struct netif *pni, struct ep *pep)
{
return OK; /* not implemented yet */
}

/* ipdstopts.c – ipdstopts */

#include
#include
#include

/*————————————————————————
* ipdstopts – do host handling of IP options
*————————————————————————
*/
int
ipdstopts(struct netif *pni, struct ep *pep)
{
struct ip *pip = (struct ip *)pep->ep_data;
u_char *popt, *popend;
int len;

if (IP_HLEN(pip) == IPMHLEN)
return OK;
popt = pip->ip_data;
popend = (u_char *)&pep->ep_data[IP_HLEN(pip)];

/* NOTE: options not implemented yet */

/* delete the options */
len = pip->ip_len-IP_HLEN(pip); /* data length */
if (len)
memcpy(pip->ip_data, &pep->ep_data[IP_HLEN(pip)], len);
pip->ip_len = IPMHLEN + len;
pip->ip_verlen = (pip->ip_verlen&0xf0) | IP_MINHLEN;
return OK;
}

问题:rtdel调用rtfree而不是使用宏 RTFREE,结果会怎么样? 会发生死锁